diff --git a/.github/workflows/docusaurus.yml b/.github/workflows/docusaurus.yml deleted file mode 100644 index a925dfe3d..000000000 --- a/.github/workflows/docusaurus.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Docusaurus - -on: - push: - paths: - - 'docusaurus/**' - - '.github/workflows/docusaurus.yml' - - workflow_dispatch: - -jobs: - push_docusaurus: - name: Publish docs - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v3.1.0 - - - name: Setup Node 18 - uses: actions/setup-node@v3.1.0 - with: - node-version: 18 - - - name: Push docs - uses: GetStream/push-stream-chat-docusaurus-action@main - with: - target-branch: ${{ github.ref == 'refs/heads/main' && 'main' || 'staging' }} - cli-target-branch: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }} - destination-repository-name: 'stream-video-docusaurus' - source-directory: 'docusaurus' - env: - DOCUSAURUS_GH_TOKEN: ${{ secrets.DOCUSAURUS_GH_TOKEN }} diff --git a/.github/workflows/vale-doc-lint.yml b/.github/workflows/vale-doc-lint.yml deleted file mode 100644 index 454572de9..000000000 --- a/.github/workflows/vale-doc-lint.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Vale - -on: - pull_request: - paths: - - 'docusaurus/**' - - '.github/workflows/vale-doc-lint.yml' - - workflow_dispatch: - -jobs: - vale: - name: Check Docusaurus docs - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: errata-ai/vale-action@reviewdog - with: - filter_mode: nofilter - reporter: github-pr-check - fail_on_error: true - files: '["docusaurus", "README.md"]' - env: - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.styles/Google/AMPM.yml b/.styles/Google/AMPM.yml deleted file mode 100644 index fbdc6e4f8..000000000 --- a/.styles/Google/AMPM.yml +++ /dev/null @@ -1,9 +0,0 @@ -extends: existence -message: "Use 'AM' or 'PM' (preceded by a space)." -link: 'https://developers.google.com/style/word-list' -level: error -nonword: true -tokens: - - '\d{1,2}[AP]M' - - '\d{1,2} ?[ap]m' - - '\d{1,2} ?[aApP]\.[mM]\.' diff --git a/.styles/Google/Acronyms.yml b/.styles/Google/Acronyms.yml deleted file mode 100644 index f41af0189..000000000 --- a/.styles/Google/Acronyms.yml +++ /dev/null @@ -1,64 +0,0 @@ -extends: conditional -message: "Spell out '%s', if it's unfamiliar to the audience." -link: 'https://developers.google.com/style/abbreviations' -level: suggestion -ignorecase: false -# Ensures that the existence of 'first' implies the existence of 'second'. -first: '\b([A-Z]{3,5})\b' -second: '(?:\b[A-Z][a-z]+ )+\(([A-Z]{3,5})\)' -# ... with the exception of these: -exceptions: - - API - - ASP - - CLI - - CPU - - CSS - - CSV - - DEBUG - - DOM - - DPI - - FAQ - - GCC - - GDB - - GET - - GPU - - GTK - - GUI - - HTML - - HTTP - - HTTPS - - IDE - - JAR - - JSON - - JSX - - LESS - - LLDB - - NET - - NOTE - - NVDA - - OSS - - PATH - - PDF - - PHP - - POST - - RAM - - REPL - - RSA - - SCM - - SCSS - - SDK - - SQL - - SSH - - SSL - - SVG - - TBD - - TCP - - TODO - - URI - - URL - - USB - - UTF - - XML - - XSS - - YAML - - ZIP diff --git a/.styles/Google/Colons.yml b/.styles/Google/Colons.yml deleted file mode 100644 index 99363fbd4..000000000 --- a/.styles/Google/Colons.yml +++ /dev/null @@ -1,8 +0,0 @@ -extends: existence -message: "'%s' should be in lowercase." -link: 'https://developers.google.com/style/colons' -nonword: true -level: warning -scope: sentence -tokens: - - ':\s[A-Z]' diff --git a/.styles/Google/Contractions.yml b/.styles/Google/Contractions.yml deleted file mode 100644 index 4f6fd5d48..000000000 --- a/.styles/Google/Contractions.yml +++ /dev/null @@ -1,30 +0,0 @@ -extends: substitution -message: "Use '%s' instead of '%s'." -link: 'https://developers.google.com/style/contractions' -level: suggestion -ignorecase: true -action: - name: replace -swap: - are not: aren't - cannot: can't - could not: couldn't - did not: didn't - do not: don't - does not: doesn't - has not: hasn't - have not: haven't - how is: how's - is not: isn't - it is: it's - should not: shouldn't - that is: that's - they are: they're - was not: wasn't - we are: we're - we have: we've - were not: weren't - what is: what's - when is: when's - where is: where's - will not: won't diff --git a/.styles/Google/DateFormat.yml b/.styles/Google/DateFormat.yml deleted file mode 100644 index e9d227fa1..000000000 --- a/.styles/Google/DateFormat.yml +++ /dev/null @@ -1,9 +0,0 @@ -extends: existence -message: "Use 'July 31, 2016' format, not '%s'." -link: 'https://developers.google.com/style/dates-times' -ignorecase: true -level: error -nonword: true -tokens: - - '\d{1,2}(?:\.|/)\d{1,2}(?:\.|/)\d{4}' - - '\d{1,2} (?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)|May|Jun(?:e)|Jul(?:y)|Aug(?:ust)|Sep(?:tember)?|Oct(?:ober)|Nov(?:ember)?|Dec(?:ember)?) \d{4}' diff --git a/.styles/Google/Ellipses.yml b/.styles/Google/Ellipses.yml deleted file mode 100644 index 1e070517b..000000000 --- a/.styles/Google/Ellipses.yml +++ /dev/null @@ -1,9 +0,0 @@ -extends: existence -message: "In general, don't use an ellipsis." -link: 'https://developers.google.com/style/ellipses' -nonword: true -level: warning -action: - name: remove -tokens: - - '\.\.\.' diff --git a/.styles/Google/EmDash.yml b/.styles/Google/EmDash.yml deleted file mode 100644 index 1befe72aa..000000000 --- a/.styles/Google/EmDash.yml +++ /dev/null @@ -1,12 +0,0 @@ -extends: existence -message: "Don't put a space before or after a dash." -link: 'https://developers.google.com/style/dashes' -nonword: true -level: error -action: - name: edit - params: - - remove - - ' ' -tokens: - - '\s[—–]\s' diff --git a/.styles/Google/EnDash.yml b/.styles/Google/EnDash.yml deleted file mode 100644 index b314dc4e9..000000000 --- a/.styles/Google/EnDash.yml +++ /dev/null @@ -1,13 +0,0 @@ -extends: existence -message: "Use an em dash ('—') instead of '–'." -link: 'https://developers.google.com/style/dashes' -nonword: true -level: error -action: - name: edit - params: - - replace - - '-' - - '—' -tokens: - - '–' diff --git a/.styles/Google/Exclamation.yml b/.styles/Google/Exclamation.yml deleted file mode 100644 index eea5fd24b..000000000 --- a/.styles/Google/Exclamation.yml +++ /dev/null @@ -1,9 +0,0 @@ -extends: existence -message: "Don't use exclamation points in text." -link: 'https://developers.google.com/style/exclamation-points' -nonword: true -level: error -action: - name: remove -tokens: - - '\w+!(?:\s|$)' diff --git a/.styles/Google/FirstPerson.yml b/.styles/Google/FirstPerson.yml deleted file mode 100644 index 0b7b8828c..000000000 --- a/.styles/Google/FirstPerson.yml +++ /dev/null @@ -1,13 +0,0 @@ -extends: existence -message: "Avoid first-person pronouns such as '%s'." -link: 'https://developers.google.com/style/pronouns#personal-pronouns' -ignorecase: true -level: warning -nonword: true -tokens: - - (?:^|\s)I\s - - (?:^|\s)I,\s - - \bI'm\b - - \bme\b - - \bmy\b - - \bmine\b diff --git a/.styles/Google/Gender.yml b/.styles/Google/Gender.yml deleted file mode 100644 index c8486181d..000000000 --- a/.styles/Google/Gender.yml +++ /dev/null @@ -1,9 +0,0 @@ -extends: existence -message: "Don't use '%s' as a gender-neutral pronoun." -link: 'https://developers.google.com/style/pronouns#gender-neutral-pronouns' -level: error -ignorecase: true -tokens: - - he/she - - s/he - - \(s\)he diff --git a/.styles/Google/GenderBias.yml b/.styles/Google/GenderBias.yml deleted file mode 100644 index 9e7019086..000000000 --- a/.styles/Google/GenderBias.yml +++ /dev/null @@ -1,47 +0,0 @@ -extends: substitution -message: "Consider using '%s' instead of '%s'." -link: 'https://developers.google.com/style/inclusive-documentation' -ignorecase: true -level: error -action: - name: replace -swap: - (?:alumna|alumnus): graduate - (?:alumnae|alumni): graduates - air(?:m[ae]n|wom[ae]n): pilot(s) - anchor(?:m[ae]n|wom[ae]n): anchor(s) - authoress: author - camera(?:m[ae]n|wom[ae]n): camera operator(s) - chair(?:m[ae]n|wom[ae]n): chair(s) - congress(?:m[ae]n|wom[ae]n): member(s) of congress - door(?:m[ae]|wom[ae]n): concierge(s) - draft(?:m[ae]n|wom[ae]n): drafter(s) - fire(?:m[ae]n|wom[ae]n): firefighter(s) - fisher(?:m[ae]n|wom[ae]n): fisher(s) - fresh(?:m[ae]n|wom[ae]n): first-year student(s) - garbage(?:m[ae]n|wom[ae]n): waste collector(s) - lady lawyer: lawyer - ladylike: courteous - landlord: building manager - mail(?:m[ae]n|wom[ae]n): mail carriers - man and wife: husband and wife - man enough: strong enough - mankind: human kind - manmade: manufactured - manpower: personnel - men and girls: men and women - middle(?:m[ae]n|wom[ae]n): intermediary - news(?:m[ae]n|wom[ae]n): journalist(s) - ombuds(?:man|woman): ombuds - oneupmanship: upstaging - poetess: poet - police(?:m[ae]n|wom[ae]n): police officer(s) - repair(?:m[ae]n|wom[ae]n): technician(s) - sales(?:m[ae]n|wom[ae]n): salesperson or sales people - service(?:m[ae]n|wom[ae]n): soldier(s) - steward(?:ess)?: flight attendant - tribes(?:m[ae]n|wom[ae]n): tribe member(s) - waitress: waiter - woman doctor: doctor - woman scientist[s]?: scientist(s) - work(?:m[ae]n|wom[ae]n): worker(s) diff --git a/.styles/Google/HeadingPunctuation.yml b/.styles/Google/HeadingPunctuation.yml deleted file mode 100644 index b538be5b4..000000000 --- a/.styles/Google/HeadingPunctuation.yml +++ /dev/null @@ -1,13 +0,0 @@ -extends: existence -message: "Don't put a period at the end of a heading." -link: 'https://developers.google.com/style/capitalization#capitalization-in-titles-and-headings' -nonword: true -level: warning -scope: heading -action: - name: edit - params: - - remove - - '.' -tokens: - - '[a-z0-9][.]\s*$' diff --git a/.styles/Google/Headings.yml b/.styles/Google/Headings.yml deleted file mode 100644 index e34d001b7..000000000 --- a/.styles/Google/Headings.yml +++ /dev/null @@ -1,28 +0,0 @@ -extends: capitalization -message: "'%s' should use sentence-style capitalization." -link: "https://developers.google.com/style/capitalization#capitalization-in-titles-and-headings" -level: warning -scope: heading -match: $sentence -indicators: - - ":" -exceptions: - - Azure - - CLI - - Cosmos - - Docker - - Emmet - - gRPC - - I - - Kubernetes - - Linux - - macOS - - Marketplace - - MongoDB - - REPL - - Studio - - TypeScript - - URLs - - Visual - - VS - - Windows diff --git a/.styles/Google/Latin.yml b/.styles/Google/Latin.yml deleted file mode 100644 index ca03b9154..000000000 --- a/.styles/Google/Latin.yml +++ /dev/null @@ -1,11 +0,0 @@ -extends: substitution -message: "Use '%s' instead of '%s'." -link: 'https://developers.google.com/style/abbreviations' -ignorecase: true -level: error -nonword: true -action: - name: replace -swap: - '\b(?:eg|e\.g\.)(?=[\s,;])': for example - '\b(?:ie|i\.e\.)(?=[\s,;])': that is diff --git a/.styles/Google/LyHyphens.yml b/.styles/Google/LyHyphens.yml deleted file mode 100644 index ac8f557a4..000000000 --- a/.styles/Google/LyHyphens.yml +++ /dev/null @@ -1,14 +0,0 @@ -extends: existence -message: "'%s' doesn't need a hyphen." -link: 'https://developers.google.com/style/hyphens' -level: error -ignorecase: false -nonword: true -action: - name: edit - params: - - replace - - '-' - - ' ' -tokens: - - '\s[^\s-]+ly-' diff --git a/.styles/Google/OptionalPlurals.yml b/.styles/Google/OptionalPlurals.yml deleted file mode 100644 index f858ea6fe..000000000 --- a/.styles/Google/OptionalPlurals.yml +++ /dev/null @@ -1,12 +0,0 @@ -extends: existence -message: "Don't use plurals in parentheses such as in '%s'." -link: 'https://developers.google.com/style/plurals-parentheses' -level: error -nonword: true -action: - name: edit - params: - - remove - - '(s)' -tokens: - - '\b\w+\(s\)' diff --git a/.styles/Google/Ordinal.yml b/.styles/Google/Ordinal.yml deleted file mode 100644 index d1ac7d27e..000000000 --- a/.styles/Google/Ordinal.yml +++ /dev/null @@ -1,7 +0,0 @@ -extends: existence -message: "Spell out all ordinal numbers ('%s') in text." -link: 'https://developers.google.com/style/numbers' -level: error -nonword: true -tokens: - - \d+(?:st|nd|rd|th) diff --git a/.styles/Google/OxfordComma.yml b/.styles/Google/OxfordComma.yml deleted file mode 100644 index b9ba21ebb..000000000 --- a/.styles/Google/OxfordComma.yml +++ /dev/null @@ -1,7 +0,0 @@ -extends: existence -message: "Use the Oxford comma in '%s'." -link: 'https://developers.google.com/style/commas' -scope: sentence -level: warning -tokens: - - '(?:[^,]+,){1,}\s\w+\s(?:and|or)' diff --git a/.styles/Google/Parens.yml b/.styles/Google/Parens.yml deleted file mode 100644 index 3b8711d0c..000000000 --- a/.styles/Google/Parens.yml +++ /dev/null @@ -1,7 +0,0 @@ -extends: existence -message: "Use parentheses judiciously." -link: 'https://developers.google.com/style/parentheses' -nonword: true -level: suggestion -tokens: - - '\(.+\)' diff --git a/.styles/Google/Passive.yml b/.styles/Google/Passive.yml deleted file mode 100644 index 3265890e5..000000000 --- a/.styles/Google/Passive.yml +++ /dev/null @@ -1,184 +0,0 @@ -extends: existence -link: 'https://developers.google.com/style/voice' -message: "In general, use active voice instead of passive voice ('%s')." -ignorecase: true -level: suggestion -raw: - - \b(am|are|were|being|is|been|was|be)\b\s* -tokens: - - '[\w]+ed' - - awoken - - beat - - become - - been - - begun - - bent - - beset - - bet - - bid - - bidden - - bitten - - bled - - blown - - born - - bought - - bound - - bred - - broadcast - - broken - - brought - - built - - burnt - - burst - - cast - - caught - - chosen - - clung - - come - - cost - - crept - - cut - - dealt - - dived - - done - - drawn - - dreamt - - driven - - drunk - - dug - - eaten - - fallen - - fed - - felt - - fit - - fled - - flown - - flung - - forbidden - - foregone - - forgiven - - forgotten - - forsaken - - fought - - found - - frozen - - given - - gone - - gotten - - ground - - grown - - heard - - held - - hidden - - hit - - hung - - hurt - - kept - - knelt - - knit - - known - - laid - - lain - - leapt - - learnt - - led - - left - - lent - - let - - lighted - - lost - - made - - meant - - met - - misspelt - - mistaken - - mown - - overcome - - overdone - - overtaken - - overthrown - - paid - - pled - - proven - - put - - quit - - read - - rid - - ridden - - risen - - run - - rung - - said - - sat - - sawn - - seen - - sent - - set - - sewn - - shaken - - shaven - - shed - - shod - - shone - - shorn - - shot - - shown - - shrunk - - shut - - slain - - slept - - slid - - slit - - slung - - smitten - - sold - - sought - - sown - - sped - - spent - - spilt - - spit - - split - - spoken - - spread - - sprung - - spun - - stolen - - stood - - stridden - - striven - - struck - - strung - - stuck - - stung - - stunk - - sung - - sunk - - swept - - swollen - - sworn - - swum - - swung - - taken - - taught - - thought - - thrived - - thrown - - thrust - - told - - torn - - trodden - - understood - - upheld - - upset - - wed - - wept - - withheld - - withstood - - woken - - won - - worn - - wound - - woven - - written - - wrung diff --git a/.styles/Google/Periods.yml b/.styles/Google/Periods.yml deleted file mode 100644 index d24a6a6c0..000000000 --- a/.styles/Google/Periods.yml +++ /dev/null @@ -1,7 +0,0 @@ -extends: existence -message: "Don't use periods with acronyms or initialisms such as '%s'." -link: 'https://developers.google.com/style/abbreviations' -level: error -nonword: true -tokens: - - '\b(?:[A-Z]\.){3,}' diff --git a/.styles/Google/Quotes.yml b/.styles/Google/Quotes.yml deleted file mode 100644 index 3cb6f1abd..000000000 --- a/.styles/Google/Quotes.yml +++ /dev/null @@ -1,7 +0,0 @@ -extends: existence -message: "Commas and periods go inside quotation marks." -link: 'https://developers.google.com/style/quotation-marks' -level: error -nonword: true -tokens: - - '"[^"]+"[.,?]' diff --git a/.styles/Google/Ranges.yml b/.styles/Google/Ranges.yml deleted file mode 100644 index 3ec045e77..000000000 --- a/.styles/Google/Ranges.yml +++ /dev/null @@ -1,7 +0,0 @@ -extends: existence -message: "Don't add words such as 'from' or 'between' to describe a range of numbers." -link: 'https://developers.google.com/style/hyphens' -nonword: true -level: warning -tokens: - - '(?:from|between)\s\d+\s?-\s?\d+' diff --git a/.styles/Google/Semicolons.yml b/.styles/Google/Semicolons.yml deleted file mode 100644 index bb8b85b42..000000000 --- a/.styles/Google/Semicolons.yml +++ /dev/null @@ -1,8 +0,0 @@ -extends: existence -message: "Use semicolons judiciously." -link: 'https://developers.google.com/style/semicolons' -nonword: true -scope: sentence -level: suggestion -tokens: - - ';' diff --git a/.styles/Google/Slang.yml b/.styles/Google/Slang.yml deleted file mode 100644 index 63f4c248a..000000000 --- a/.styles/Google/Slang.yml +++ /dev/null @@ -1,11 +0,0 @@ -extends: existence -message: "Don't use internet slang abbreviations such as '%s'." -link: 'https://developers.google.com/style/abbreviations' -ignorecase: true -level: error -tokens: - - 'tl;dr' - - ymmv - - rtfm - - imo - - fwiw diff --git a/.styles/Google/Spacing.yml b/.styles/Google/Spacing.yml deleted file mode 100644 index 66e45a6b7..000000000 --- a/.styles/Google/Spacing.yml +++ /dev/null @@ -1,10 +0,0 @@ -extends: existence -message: "'%s' should have one space." -link: 'https://developers.google.com/style/sentence-spacing' -level: error -nonword: true -action: - name: remove -tokens: - - '[a-z][.?!] {2,}[A-Z]' - - '[a-z][.?!][A-Z]' diff --git a/.styles/Google/Spelling.yml b/.styles/Google/Spelling.yml deleted file mode 100644 index 527ac07d3..000000000 --- a/.styles/Google/Spelling.yml +++ /dev/null @@ -1,10 +0,0 @@ -extends: existence -message: "In general, use American spelling instead of '%s'." -link: 'https://developers.google.com/style/spelling' -ignorecase: true -level: warning -tokens: - - '(?:\w+)nised?' - - 'colour' - - 'labour' - - 'centre' diff --git a/.styles/Google/Units.yml b/.styles/Google/Units.yml deleted file mode 100644 index 53522ab2d..000000000 --- a/.styles/Google/Units.yml +++ /dev/null @@ -1,8 +0,0 @@ -extends: existence -message: "Put a nonbreaking space between the number and the unit in '%s'." -link: "https://developers.google.com/style/units-of-measure" -nonword: true -level: error -tokens: - - \b\d+(?:B|kB|MB|GB|TB) - - \b\d+(?:ns|ms|s|min|h|d) diff --git a/.styles/Google/We.yml b/.styles/Google/We.yml deleted file mode 100644 index c7ac7d362..000000000 --- a/.styles/Google/We.yml +++ /dev/null @@ -1,11 +0,0 @@ -extends: existence -message: "Try to avoid using first-person plural like '%s'." -link: 'https://developers.google.com/style/pronouns#personal-pronouns' -level: warning -ignorecase: true -tokens: - - we - - we'(?:ve|re) - - ours? - - us - - let's diff --git a/.styles/Google/Will.yml b/.styles/Google/Will.yml deleted file mode 100644 index 128a91836..000000000 --- a/.styles/Google/Will.yml +++ /dev/null @@ -1,7 +0,0 @@ -extends: existence -message: "Avoid using '%s'." -link: 'https://developers.google.com/style/tense' -ignorecase: true -level: warning -tokens: - - will diff --git a/.styles/Google/WordList.yml b/.styles/Google/WordList.yml deleted file mode 100644 index 2ac43304c..000000000 --- a/.styles/Google/WordList.yml +++ /dev/null @@ -1,81 +0,0 @@ -extends: substitution -message: "Use '%s' instead of '%s'." -link: "https://developers.google.com/style/word-list" -level: warning -ignorecase: false -action: - name: replace -swap: - "(?:API Console|dev|developer) key": API key - "(?:cell ?phone|smart ?phone)": phone|mobile phone - "(?:dev|developer|APIs) console": API console - "(?:e-mail|Email|E-mail)": email - "(?:file ?path|path ?name)": path - "(?:kill|terminate|abort)": stop|exit|cancel|end - "(?:OAuth ?2|Oauth)": OAuth 2.0 - "(?:ok|Okay)": OK|okay - "(?:WiFi|wifi)": Wi-Fi - '[\.]+apk': APK - '3\-D': 3D - 'Google (?:I\-O|IO)': Google I/O - "tap (?:&|and) hold": touch & hold - "un(?:check|select)": clear - above: preceding - account name: username - action bar: app bar - admin: administrator - Ajax: AJAX - a\.k\.a|aka: or|also known as - Android device: Android-powered device - android: Android - API explorer: APIs Explorer - application: app - approx\.: approximately - authN: authentication - authZ: authorization - autoupdate: automatically update - cellular data: mobile data - cellular network: mobile network - chapter: documents|pages|sections - check box: checkbox - check: select - CLI: command-line tool - click on: click|click in - Cloud: Google Cloud Platform|GCP - Container Engine: Kubernetes Engine - content type: media type - curated roles: predefined roles - data are: data is - Developers Console: Google API Console|API Console - disabled?: turn off|off - ephemeral IP address: ephemeral external IP address - fewer data: less data - file name: filename - firewalls: firewall rules - functionality: capability|feature - Google account: Google Account - Google accounts: Google Accounts - Googling: search with Google - grayed-out: unavailable - HTTPs: HTTPS - in order to: to - ingest: import|load - k8s: Kubernetes - long press: touch & hold - network IP address: internal IP address - omnibox: address bar - open-source: open source - overview screen: recents screen - regex: regular expression - SHA1: SHA-1|HAS-SHA1 - sign into: sign in to - sign-?on: single sign-on - static IP address: static external IP address - stylesheet: style sheet - synch: sync - tablename: table name - tablet: device - touch: tap - url: URL - vs\.: versus - World Wide Web: web \ No newline at end of file diff --git a/.styles/Google/meta.json b/.styles/Google/meta.json deleted file mode 100644 index a5da2a848..000000000 --- a/.styles/Google/meta.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "feed": "https://github.com/errata-ai/Google/releases.atom", - "vale_version": ">=1.0.0" -} diff --git a/.styles/Google/vocab.txt b/.styles/Google/vocab.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/.styles/config/vocabularies/Base/accept.txt b/.styles/config/vocabularies/Base/accept.txt deleted file mode 100644 index ae9f0be6b..000000000 --- a/.styles/config/vocabularies/Base/accept.txt +++ /dev/null @@ -1,42 +0,0 @@ -viewport -Viewport -[Tt]ooltip -SDKs -100ms -Giphy -Angular -API -timeframe -APNs -Telehealth -telemedicine -[Ff]lutter -Podfile -protobuf -protos -proto -[Ll]ivestream -grayscale -uni_links -browsable -keystore -keystores -Xcode -melos -Melos -env -UIs -const -Geofencing -mixin -permission_handler -unmuting -lecle_yoyo_player -stream_video -stream_video_push_notification -screensharing -[Ss]creen[Ss]hare -Livestreaming -livestreaming -callee -audio_room \ No newline at end of file diff --git a/.styles/config/vocabularies/Base/reject.txt b/.styles/config/vocabularies/Base/reject.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vale.ini b/.vale.ini deleted file mode 100644 index cfae0f799..000000000 --- a/.vale.ini +++ /dev/null @@ -1,18 +0,0 @@ -StylesPath = .styles - -MinAlertLevel = error -Vocab = Base - -Packages = Google - -# The "formats" section allows you to associate an "unknown" format -# with one of Vale's supported formats. -[formats] -mdx = md - -# Since we mapped `mdx` to `md` in the `formats`section we have to declare our format to be `md` -[*.md] -BasedOnStyles = Vale, Google -BlockIgnores = (^import .*;), (import .*;), (\n(.*\n)+
), (\| .* \|), () - -TokenIgnores = (^import .*;),(import .*;) diff --git a/development.md b/development.md index 377666867..dcf0519f9 100644 --- a/development.md +++ b/development.md @@ -60,20 +60,25 @@ - [x] Transcription ### 0.5.0 milestone -- [ ] Documentation parity -- - [ ] UI components -- - [ ] Cookbook -- - [ ] Advanced guides -- [ ] Tap to focus (flutter_webrtc) -- [ ] Video filters / audio filters +- [x] Reconnection v2 +- [x] Documentation parity +- - [x] UI components +- - [x] Cookbook +- - [x] Advanced guides +- [x] Dynascale 2.0 +- [x] SFU switching + +### 0.6.0 milestone +- [x] Video filters +- [ ] Closed captions + +### 0.7.0 milestone +- [ ] Codec preference - [ ] Local audio levels (maybe from webrtc) +- [ ] Audio filters (noice cancelling) +- [ ] Tap to focus (flutter_webrtc) - [ ] Test coverage - - [ ] stream_video (75%) - - [ ] stream_video_flutter (75%) - - [ ] stream_video_push_notification -- - [ ] Coverage check for PRs -- [ ] Dynascale 2.0 -- [ ] SFU switching -- [ ] Buttons to simulate ICE restarts / SFU switching -- [ ] Proximity button support -- [ ] Reconnection v2 +- - [ ] Coverage check for PRs \ No newline at end of file diff --git a/docusaurus/.env b/docusaurus/.env deleted file mode 100644 index e9f70f9cf..000000000 --- a/docusaurus/.env +++ /dev/null @@ -1 +0,0 @@ -PRODUCT=video diff --git a/docusaurus/docs/Flutter/01-setup/01-introduction.mdx b/docusaurus/docs/Flutter/01-setup/01-introduction.mdx deleted file mode 100644 index 0d8b5106f..000000000 --- a/docusaurus/docs/Flutter/01-setup/01-introduction.mdx +++ /dev/null @@ -1,35 +0,0 @@ ---- -slug: / -title: Introduction -description: Introduction to Stream's Video SDK ---- - - -Welcome to the [Stream Video Flutter SDK](https://getstream.io/video/sdk/flutter/) - a comprehensive toolkit designed to help you swiftly implement features such as video calling, audio calling, audio rooms, and livestreaming within your app. - -Our goal is to ensure an optimal developer experience that enables your application to go live within days. - -Our Flutter SDK is furnished with user-friendly UI components and versatile state objects, making your development process seamless. -Moreover, all calls are routed through Stream's global edge network, thereby ensuring lower latency and higher reliability due to proximity to end users. - -If you're new to Stream Video SDK, we recommend starting with the following three tutorials: -- [Video & Audio Calling Tutorial](https://getstream.io/video/sdk/flutter/tutorial/video-calling/) -- [Audio Room Tutorial](https://getstream.io/video/sdk/flutter/tutorial/audio-room/) -- [Livestream Tutorial](https://getstream.io/video/sdk/flutter/tutorial/livestreaming/) - -After the tutorials, the documentation explains how to use the - -* Core concepts such as initiating a call, switching the camera view, and more -* Effective utilization of our UI components -* Insights on building your own UI with our UI Cookbook - - It also explains advanced features such as: - - * Picture-in-Picture support - * Ringing - * Recording - * Broadcasting - * Requesting & Granting permissions - * Audio & Video Filters - - If you feel like anything is missing or could be improved, please don't hesitate to [contact us](product@getstream.io). We're happy to help. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/01-setup/02-installation.mdx b/docusaurus/docs/Flutter/01-setup/02-installation.mdx deleted file mode 100644 index 89018eb70..000000000 --- a/docusaurus/docs/Flutter/01-setup/02-installation.mdx +++ /dev/null @@ -1,97 +0,0 @@ ---- -slug: /installation -title: Installation ---- - -The Flutter SDK for Stream Video is distributed through [pub.dev](https://pub.dev). -The SDK contains four different packages: [stream_video_flutter](https://pub.dev/packages/stream_video_flutter), [stream_video](https://pub.dev/packages/stream_video), [stream_video_push_notification](https://pub.dev/packages/stream_video_push_notification) and [stream_video_screen_sharing](https://pub.dev/packages/stream_video_screen_sharing). -Releases and changes are published on the [GitHub releases page](https://github.com/GetStream/stream-video-flutter/releases). - -### Adding the SDK to your project - -To add the Flutter SDK, you can add the latest dependencies for the SDK to your `pubspec.yaml` file: - -```yaml -dependencies: - -stream_video: ^latest -stream_video_flutter: ^latest -stream_video_push_notification: ^latest -stream_video_screen_sharing: ^latest -``` - -Additionally, you can also run the `flutter pub add` command in the terminal to do this: - -```shell -flutter pub add stream_video_flutter -flutter pub add stream_video -flutter pub add stream_video_push_notification -flutter pub add stream_video_screen_sharing -``` - -This command will automatically install the latest versions of the Stream SDK packages from pub.dev to the dependencies section of your `pubspec.yaml`. - -### Permissions - -Making video calls requires the usage of the device's camera and microphone. Therefore, before you can make and answer calls, you need to request permission to use them within your application. - -The following permissions must be granted for both Android and iOS: - -- Internet Connectivity -- Camera -- Microphone (+ control audio settings to adjust audio level & switch between speaker & earpiece) -- Bluetooth (wireless headset) - -#### iOS - -![Xcode Permission configuration](../assets/installation/ios_permission.png) - -For iOS, we recommend you add the following keys and values to your `Info.plist` file at a minimum: - - ```plist -NSCameraUsageDescription -$(PRODUCT_NAME) needs access to your camera for video calls. -NSMicrophoneUsageDescription -$(PRODUCT_NAME) needs access to your microphone for voice and video calls. -UIApplicationSupportsIndirectInputEvents - -BGTaskSchedulerPermittedIdentifiers - - $(PRODUCT_BUNDLE_IDENTIFIER) - -UIBackgroundModes - - audio - fetch - processing - remote-notification - voip - -``` - -#### Android - -For Android, similar permissions are needed in `/android/app/src/main/AndroidManifest.xml` - -```xml - - - - - - - -``` - -With Android specifically, you will also need to add additional permission if you would like to use Bluetooth devices: - -```xml - - - -``` - -### VoIP Calling - -We also ship the [stream_video_push_notification](https://pub.dev/packages/stream_video_push_notification) package to allow you to add integrations with native calling interfaces such as [CallKit](https://developer.apple.com/documentation/callkit/). -Please check out our [ringing guide](https://getstream.io/video/docs/flutter/advanced/ringing_and_callkit/) for additional setup needed for integration. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/01-setup/03-quickstart.mdx b/docusaurus/docs/Flutter/01-setup/03-quickstart.mdx deleted file mode 100644 index 52158ccd8..000000000 --- a/docusaurus/docs/Flutter/01-setup/03-quickstart.mdx +++ /dev/null @@ -1,185 +0,0 @@ ---- -slug: /quickstart -title: Quickstart ---- - -The Flutter Video for Stream Video is a highly customizable SDK that facilitates adding calling (audio and video) support to your apps. - -The SDK consists of four parts: - -* Low-level client ([stream_video](https://pub.dev/packages/stream_video)): Responsible for establishing calls, built on top of WebRTC. -* UI SDK ([stream_video_flutter](https://pub.dev/packages/stream_video_flutter)): Flutter widgets for different types of call flows. -* VoIP SDK ([stream_video_push_notification](https://pub.dev/packages/stream_video_push_notification)): Adds native calling interface support for Android and iOS (CallKit). -* Screen sharing SDK ([stream_video_screen_sharing](https://pub.dev/packages/stream_video_screen_sharing)): Includes a native Swift implementation of `BroadcastSampleHandler`, essential for the `broadcast` screen sharing mode on iOS. - -In this guide, we will build a video calling app that shows how you can integrate the SDK in few simple steps. - -If you haven't already, we recommend starting with the [introduction](https://getstream.io/video/docs/flutter/) and [installation](https://getstream.io/video/docs/flutter/installation/) steps first, as this guide will build on the material covered in those sections. - -### Client Setup - -Before we can create a new video client, we must first import the Stream Video package into our application. - -```dart -import 'package:stream_video_flutter/stream_video_flutter.dart'; -``` - -Next, in our application’s `main` function, let’s add the following: - -```dart -Future main() async { - // Ensure Flutter is able to communicate with Plugins - WidgetsFlutterBinding.ensureInitialized(); - - // Initialize Stream video and set the API key along with the user for our app. - final client = StreamVideo( - 'REPLACE_WITH_API_KEY', - user: User.regular(userId: 'REPLACE_WITH_USER_ID', name: 'Test User'), - userToken: 'REPLACE_WITH_TOKEN', - ); - - // Set up our call object and pass it the call type and ID. The most common call type is `default`, which enables full audio and video transmission - final call = client.makeCall(callType: StreamCallType.defaultType(), id: 'REPLACE_WITH_CALL_ID'); - // Connect to the call we created - await call.join(); - - runApp( - DemoAppHome( - call: call, - ), - ); -} -``` - -In the code above, we are performing a few key steps: - -1. Initializing our SDK with the API key for our application. -2. Defining the user we would like to connect as to participate in a call. -3. Creating an object for our call, giving it the "default" call type and unique ID. -4. Connecting to the call we defined. - - -Although it is not shown in the example above, users can choose to customize many different aspects of the SDK during initialization. Here are a few of the parameters which can be overridden during initialization: - -| Parameter | Description | -| --- | --- | -| apiKey | Stream Video API key obtained from the Dashboard of your project. | -| latencySettings | Controls the number of rounds and timeout duration for measuring latency when first connecting to a call. | -| retryPolicy | Allows for custom handling of retries such as override the default number of max retries, passing in a custom backoff function and more. | -| sdpPolicy | Controls whether SDP Munging is enabled and gives access to functions supporting SDP Munging. | -| logPriority | Allows for customizing the level of logs displayed while developing or running your application. | -| logHandlerFunction | Can be overridden to intercept logs and perform custom actions such as sending device logs to a capture service. | -| muteVideoWhenInBackground | Indicates whether the SDK should disable the video track when the app moves from the foreground to background. We highly recommend you set this to true if your app does not support picture-in-picture mode. | -| muteAudioWhenInBackground | Indicates whether the SDK should disable the audio track when the app moves from the foreground to background. We highly recommend you set this to true if your app does not support picture-in-picture mode. | - -### Call UI - -Stream ships with many pre-made components to make building your call UI as simple as possible. All of our UI components are designed to be flexible and customizable, meaning as a developer, you can control exactly how much (or how little) of Stream’s stock components you would like to have in your app. - -With our `Call` object defined, let’s create the UI for our application. Since this is meant to be a quick-start guide, we can simply pass down the `call` defined earlier to our UI widget, but in a production scenario, you can define these calls in a repository or any other state layer of your choice. - -```dart -class DemoAppHome extends StatelessWidget { - const DemoAppHome({Key? key, required this.call}) : super(key: key); - - final Call call; - - @override - Widget build(BuildContext context) { - return Scaffold( - body: StreamCallContainer( // Stream's pre-made component - call: call, - ), - ); - } -} -``` - -Using our default `StreamCallContainer` along with the `call` created earlier, we can compile our sample application and examine the result. - -![Completed application](../assets/quick_start_assets/completed_app.png) - -In just a few lines of code, we can have a fully functional call screen in our application. Out of the box, `StreamCallContainer` ships with an AppBar, Participant view, and Call Controls. These components can be themed to fit your app's style or be overridden entirely using a builder to allow for custom UIs and interactions. - -### Taking it one step further - -For fun, let's take a look at customizing the UI of our application to include a custom icon in the control area. - -![Call control area](../assets/quick_start_assets/call_control_area.png) - -Looking at our current UI code, we can make use of Flutter’s composition and builder pattern to override the default UI with our own. - -```dart -@override - Widget build(BuildContext context) { - return Scaffold( - body: StreamCallContainer( - call: call, - callContentBuilder: (context, call, callState) { - }, - ), - ); - } -``` - -`StreamCallContainer` ships with many different builders that can be implemented to override the default UI and behavior. Since we are interested in changing the content/UI of our call, we can override the `callContentBuilder` as a starting point. - -:::note - Please take a minute to explore and look at the other parameters you can customize. There are many options for changing colors, layouts, behaviour, etc. -::: - -Next, we can use another Stream UI component, `StreamCallContent` to access the control area and add our custom button. - -```dart -@override - Widget build(BuildContext context) { - return Scaffold( - body: StreamCallContainer( - call: call, - callContentBuilder: (context, call, callState) { - return StreamCallContent( - call: call, - callState: callState, - callControlsBuilder: (context, call, callState) { - // Override the controls builder in StreamCallContent - }, - ); - }, - ), - ); - } -``` - -Finally, we can return the controls and options we would like to display to the user - -```dart -return StreamCallContent( - call: call, - callState: callState, - callControlsBuilder: (context, call, callState) { - final localParticipant = callState.localParticipant!; - return StreamCallControls( - options: [ - CallControlOption( - icon: const Text('👋'), - onPressed: () => ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Hello'), - ), - ), - ), - FlipCameraOption( - call: call, - localParticipant: localParticipant, - ), - LeaveCallOption(call: call, onLeaveCallTap: call.leave), - ], - ); - }, - ); -``` - -![Modified Call UI](../assets/quick_start_assets/modified_ui.png) - -When tapped: -![Display banner](../assets/quick_start_assets/display_banner.png) \ No newline at end of file diff --git a/docusaurus/docs/Flutter/01-setup/_category_.json b/docusaurus/docs/Flutter/01-setup/_category_.json deleted file mode 100644 index ece9ba735..000000000 --- a/docusaurus/docs/Flutter/01-setup/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Setup" -} diff --git a/docusaurus/docs/Flutter/03-core-concepts/01-authentication.mdx b/docusaurus/docs/Flutter/03-core-concepts/01-authentication.mdx deleted file mode 100644 index 1ae35e2c9..000000000 --- a/docusaurus/docs/Flutter/03-core-concepts/01-authentication.mdx +++ /dev/null @@ -1,174 +0,0 @@ ---- -slug: /client-and-authentication -title: Client and Authentication -sidebar_position: 1 ---- - -import { TokenSnippet } from '../../../shared/_tokenSnippet.jsx'; - -`StreamVideo` is the main class used for creating class, performing authentication and listening to core events dispatched by Stream’s servers. - -Before joining a call, it is necessary to set up the video client. Here's a basic example: - - ```dart - final client = StreamVideo( - 'REPLACE_WITH_API_KEY', - user: User.regular( - userId: 'REPLACE_WITH_USER_ID', - name: 'John Doe', - ), - userToken: 'REPLACE_WITH_TOKEN', - ); - ``` - -* The API Key can be found in your Stream dashboard. -* The User can be either authenticated, anonymous or guest. -* Note: You can store custom data on the user object, if required. - -`StreamVideo` is the main class used for creating class, performing authentication and listening to core events dispatched by Stream’s servers. - -The initialization constructor for `StreamVideo` also exposes many customization options which can be overridden based on the project needs such as the logging level, SDP policy, retry policy, etc. - -```dart -factory StreamVideo( - String apiKey, { - StreamVideoOptions options = StreamVideoOptions( - coordinatorRpcUrl: _defaultCoordinatorRpcUrl, - coordinatorWsUrl: _defaultCoordinatorWsUrl, - latencySettings: const LatencySettings(), - sdpPolicy: const SdpPolicy(), - retryPolicy: const RetryPolicy(), - logPriority: Priority.none, - logHandlerFunction: _defaultLogHandler, - muteVideoWhenInBackground: false, - muteAudioWhenInBackground: false, - autoConnect: true, - includeUserDetailsForAutoConnect: true, - keepConnectionsAliveWhenInBackground: false, - ), - required User user, - String? userToken, - TokenLoader? tokenLoader, - OnTokenUpdated? onTokenUpdated, - bool failIfSingletonExists = true, - PNManagerProvider? pushNotificationManagerProvider, -}); -``` - -:::note -The SDK tries to connect to Stream's backend automatically by default. You can set `autoConnect` to false in `StreamVideoOptions` to change this behaviour. -::: - -If you choose to connect later, you can use the `connect()` method to connect to Stream Video: - -```dart - StreamVideo.instance.connect(); -``` - -The connection passes the user info by default to the backend. -To change this, you can set the `includeUserDetailsForAutoConnect` parameter in `StreamVideoOptions` when auto-connecting -or use the `includeUserDetails` parameter when using the `connect()` method: - -```dart - StreamVideo.instance.connect( - includeUserDetails: false, - ); -``` - -### Working with Tokens - -All tokens must be generated via a backend SDK and cannot be created from a frontend client. This step is typically included whenever a new user is registered on your backend. - -Here's a valid user and token to help you get started on the client side, before integrating with your backend API. - - - -There are a few ways in which users can connect using our SDK. -We support both long lived tokens and dynamic tokens via two parameters accessible on the `StreamVideo` class: - -- `StreamVideo(apiKey, user: User, userToken: String)` -- `StreamVideo(apiKey, user: User, tokenLoader: TokenLoader)` - -For situations where your backend does not require tokens to be refreshed, the first variant of the two above can be used by simply passing in a `User` object and the `userToken` as a `String`. - -Using the second variant, a Token Loader can be used to dynamically load a token from a server. On expiration, the SDK automatically calls the Token Loader to obtain a new token. - -As long as your handler returns a `String` it will satisfy the contract of `TokenLoader`. -Here is an example of how you could write the token loader - -```dart -Future _tokenLoader(String userId) async { - final token = await backend.loadToken( - apiKey: Env.apiKey, - userId: userId, - ); - return token; -} -``` - -```dart -StreamVideo( - apiKey, - user: user, - tokenLoader: _tokenLoader, - onTokenUpdated: (token) async { - // Callback function with the token. - // Called when the token is updated. - }, -); -``` - -### Guest / Anonymous users - -For use-cases like live streaming or guest meeting, you may want to allow users to join a call without creating an account. - -#### Guest Users - -For these use-cases, the SDK has a guest endpoint which can be used to create a temporary user - -```dart -final guest = User.guest(userId: guestId, name: guestName, image: guestImage); -final client = StreamVideo( - apiKey, - user: guest, -); - -final result = await client.connect(); -// if result wasn't successful, then result will return null -final userToken = result.getDataOrNull(); -final userInfo = client.currentUser; -``` - -:::note -`userInfo.id` will be slightly different from what you passed in. This is because the SDK will generate a unique ID for the user. -Please use the generated ID across your app. -::: - -#### Anonymous Users - -```dart -final anonymous = User.anonymous(); -final client = StreamVideo( - apiKey, - user: anonymous, -); -``` - -Anonymous users don't establish an active web socket connection, therefore they won't receive any events. They are just able to watch a livestream or join a call. - -The token for an anonymous user should contain the `call_cids` field, which is an array of the call `cid`'s that the user is allowed to join. - -Here's an example JWT token payload for an anonymous user: - -```swift -{ - "iss": "@stream-io/dashboard", - "iat": 1726406693, - "exp": 1726493093, - "user_id": "!anon", - "role": "viewer", - "call_cids": [ - "livestream:123" - ] -} -``` \ No newline at end of file diff --git a/docusaurus/docs/Flutter/03-core-concepts/02-joining-and-creating-calls.mdx b/docusaurus/docs/Flutter/03-core-concepts/02-joining-and-creating-calls.mdx deleted file mode 100644 index 81c5b2dee..000000000 --- a/docusaurus/docs/Flutter/03-core-concepts/02-joining-and-creating-calls.mdx +++ /dev/null @@ -1,160 +0,0 @@ ---- -slug: /joining-and-creating-calls -title: Joining and Creating Calls -sidebar_position: 2 ---- - -### Creating Calls - -To create a call, we first call the `makeCall` function on the `StreamVideo` class and pass it the call type and ID. -The most common call type is `default`, which enables full audio and video transmission. -However, there are multiple call types (and even custom types) from which you can choose based on your use case. - -Call type | Name | Short overview ---- | --- | --- -default | Default | simple 1-1 calls for larger group video calling with sensible defaults -audio_room | Audio | pre-configured for a workflow around requesting permissions in audio settings (speaking, etc.) -livestream | Livestream | access to calls is granted to all authenticated users, useful in one-to-many settings (such as livestreaming) -development | Development | should only be used for testing, permissions are open and everything is enabled (use carefully) - -You can read more about call types [here](https://getstream.io/video/docs/flutter/call-types/). - - -```dart -final call = StreamVideo.instance.makeCall(callType: StreamCallType.defaultType(), id: 'Your-call-ID'); -await call.getOrCreate(); -``` - -Calling `makeCall` returns a `Call` object for us to work with. However, it neither connects nor starts transmitting data automatically. -To create and join the call, we must then invoke `getOrCreate` on the returned object which creates the call if it doesn't exist and returns the existing call if it does. - -For the call ID there are a few things to note: - -* You can reuse the same call multiple times. -* If you have a unique id for the call we recommend passing that as the id. -* If you don't have a unique id you can leave it empty and we'll generate one for you. - -As an example, if you're building a telemedicine app, calls will be connected to an appointment. Using your own appointment id as the **Call ID** makes it easy to find the call later. - -### Managing Members and Ringing Calls - -You can pass certain arguments to the `call.getOrCreate()` method used in the previous example: - -1. `members`: Upon creation, we can supply a list of user IDs we would like to immediately add to the call. -2. `ringing`: If ringing is set to `true`, Stream will send a VoIP notification to the users on the call, triggering the platform call screen on iOS and Android. -3. `video`: When ringing, the notification will indicate whether it's a video call or an audio-only call, depending on whether you set the `video` parameter to true or false. -4. `custom`: Any custom data associated with the call. -5. `team`: A team is a part of [Stream Video multi-tenancy support](https://getstream.io/video/docs/api/multi-tenant/). You can separate different groups of videos and calls using this argument. -6. `notify` If notify is set to true, Stream will send a standard non-VoIP push notification to all the users in the call. - -:::note -By default, calling `getOrCreate()` assigns `admin` permission to each user who is supplied during creation. Depending on call permissions settings, call member may have different permissions than other users joining the call. For example, call can be configured so only members can join. See [here](#restricting-access) for more information. -::: - -When call is already active you can still manage members: - -```dart -final call = client.makeCall(callType: StreamCallType.defaultType(), id: 'my-call-id'); -call.getOrCreate(memberIds: ['alice', 'bob']); - -// grant access to more users -await call.updateCallMembers(updateMembers: [const UserInfo(id: 'charlie', role: 'call_member')]); -// or -await call.addMembers([const UserInfo(id: 'charlie', role: 'call_member')]); - -// remove access from some users -await call.updateCallMembers(removeIds: ['charlie']); -// or -await call.removeMembers(['charlie']); -``` - -### Call CRUD Operations - -With calls, we make it easy to perform basic create, read, update, and delete (CRUD) operations on calls providing the user has sufficient permissions. - -For example, once a call is created a user can `call.update` the information on the call by adding custom metadata such as a name, description, or any other arbitrary `Map` to the call before `getOrCreate` is invoked. - -```dart -call.update(custom: {'name': 'My first Call'}); -await call.getOrCreate(); -``` - -Using the update method, a variety of settings can also be applied before the call is created such as: - -- Ring -- Audio -- Video -- ScreenShare -- Recording -- Transcription -- Backstage -- Geofencing - -### Joining Calls - -To join a call that already exists, you must first know two things: - -- The `callType` of the existing call -- The `ID` of the existing call - -Similar to the flow of creating a call, we can use `makeCall` to construct a `Call` class for us to perform operations on. - -```dart -final call = StreamVideo.instance.makeCall(callType: StreamCallType.defaultType(), id: 'My-existing-call-ID'); -await call.getOrCreate(); -``` - -Next, with our class instantiated, we can connect to the call and SFU by invoking `join`. - -```dart -await call.join(); -``` - -Unlike the call creation flow and functions, the user must have sufficient permissions to join the call or a `VideoError` will be returned. All users connected via the `join()` function have the permission type of `user` by default and are limited in the actions they can perform. - -#### Backstage setup - -The backstage feature makes it easy to build a use-case where you and your co-hosts can setup your camera before going live. Only after you call `call.goLive()` the regular users be allowed to join the livestream. - -However, you can also specify a `joinAheadTimeSeconds`, which allows regular users to join the livestream before it is live, in the specified join time before the stream starts. - -Here's an example how to do that: - -```dart -final call = StreamVideo.instance.makeCall(callType: StreamCallType.livestream(), id: 'my-call-id'); - -const backstageSetting = StreamBackstageSettings( - enabled: true, - joinAheadTimeSeconds: 300, -); - -await call.getOrCreate( - memberIds: ['alice', 'bob'], - startsAt: DateTime.now().add(const Duration(seconds: 500)), - backstage: backstageSetting, -); - -await call.join(); -``` - -In the code snippet above, we are creating a call that starts 500 seconds from now. We are also enabling backstage mode, with a `joinAheadTimeSeconds` of 300 seconds. That means that regular users will be able to join the call 200 seconds from now. - -### Restricting access - -You can restrict access to a call by tweaking the [Call Type](https://getstream.io/video/docs/flutter/call-types/) permissions and roles. A typical use case is to restrict access to a call to a specific set of users -> call members. - -#### Step 1: Set up the roles and permissions -​ -On our [dashboard](https://dashboard.getstream.io), navigate to the **Video & Audio -> Roles & Permissions** section and select the appropriate role and scope. In this example, we will use `my-call-type` scope. - -By default, all users unless specified otherwise, have the `user` role. - -We start by removing the `JoinCall` permission from the `user` role for the `my-call-type` scope. It will prevent regular users from joining a call of this type. - -![Revoke JoinCall](../assets/core_concepts/user-revoke-joincall.png) - -Next, let's ensure that the `call_member` role has the `JoinCall` permission for the `my-call-type` scope. It will allow users with the `call_member` role to join a call of this type. - -![Grant JoinCall](../assets/core_concepts/call_member-grant-joincall.png) - -Once this is set, we can proceed with setting up a call instance. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/03-core-concepts/03-call-state.mdx b/docusaurus/docs/Flutter/03-core-concepts/03-call-state.mdx deleted file mode 100644 index a2a5068ef..000000000 --- a/docusaurus/docs/Flutter/03-core-concepts/03-call-state.mdx +++ /dev/null @@ -1,142 +0,0 @@ ---- -slug: /call-and-participant-state -title: Call and Participant State -sidebar_position: 3 ---- - -When you join a call, we'll automatically expose state in 3 different places: the Stream Video Client, the Call, and the participants. - -```dart -var clientState = streamVideo.state; -var callState = call.state; -var participants = call.state.value.callParticipants; -``` - - ### Call State - -When a `Call` is created, users can subscribe to receive notifications about any changes that may occur during the call's lifecycle. -To access the state of a call, use `call.state.value` to obtain the latest `CallState` snapshot, or use `valueStream` to listen for real-time changes to the `CallState`. - -This functionality is particularly useful for determining which parts of the UI or application to render based on the current state or lifecycle of the ongoing call. - -For example, you may want to display an indicator to users when a call is being recorded: - -```dart -StreamBuilder( - stream: call.state.valueStream, // Subscribe to state changes - builder: (context, snapshot) { - final state = snapshot.data; - if (state.isRecording) { - return CallRecordingUI(); - } else { - return RegularCallUI(); - } - }, -), -``` - -The following fields are available on the call: - -| Attribute | Description| -| --------- | ---------- | -| `currentUserId` | The user ID of the local user. | -| `callParticipants` | The list of call participants. | -| `isRingingFlow` | If this call has `ringing` set to true. | -| `sessionId` | The current session ID for the call. | -| `status` | The current call state - see next section for more information. | -| `liveStartedAt` | When call was set as live. | -| `liveEndedAt` | When call was set as not live. | -| `localParticipant` | Shortcut to your own participant state. | -| `otherParticipants` | The list of call participants other than yourself. | -| `isRecording` | If the call is being recorded or not. | -| `settings` | The settings for this call. | -| `ownCapabilities` | Which actions you have permission to do. | -| `capabilitiesByRole` | What different roles (user, admin, moderator etc.) are allowed to do. | -| `isBackstage` | If a call is in backstage mode or not. | -| `isBroadcasting` | If a call is broadcasting (to HLS) or not. | -| `createdAt` | When the call was created. | -| `startsAt` | When the call is scheduled to start. | -| `endedAt` | When the call ended. | -| `createdByUserId` | User ID which created the call. | -| `isTranscribing` | A boolean indicating if transcriptions are active or or not for this call. | -| `egress` | Contains URL for playlist of recording. | -| `reconnectionStatus` | whether the call is reconnecting. | -| `duration` | The duration of the call. | - - -## Understanding Call Status - -The `status` property of the `CallState` object indicates the current state of the call. Depending on where you are in the call lifecycle, `CallStatus` can have one of the following possible values. - -| Call Status | Description | -| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -| CallStatusIdle | Indicates that there is no active call at the moment. | -| CallStatusIncoming | Indicates that there’s an incoming call, and you need to display an incoming call screen. | -| CallStatusOutgoing | Indicates that the user is making an outgoing call, and you need to display an outgoing call screen. | -| CallStatusConnecting | | -| CallStatusReconnecting | Indicates that the SDK is attempting to reconnect to the call. The number of attempts can be set via the attempt property. | -| CallStatusConnected | Indicates that the user is connected to the call and is ready to send and receive tracks. | -| CallStatusDisconnected | Indicates that the call has ended, failed, or has been canceled. The exact reason can be accessed via the DisconnectedReason property. | -| CallStatusJoining | | -| CallStatusJoined | Indicates that the user has successfully joined the call. | - -By checking the `CallStatus` value in the `CallState` object, you can determine the current state of the call and adjust your UI accordingly. - -### Participant State - -```dart -var participants = call.state.value.callParticipants; -var localParticipant = call.state.value.localParticipant; -``` - -In the call state, you can find the parameter `callParticipants`. This parameter allows you to access and manipulate the participants present on the call. By using `callParticipants`, you can easily map over the participants and observe changes in their configuration. -For instance, you can keep track of which participant is currently speaking, which participant is the dominant speaker, and which participant is pinned to the call. Additionally, `callParticipants` allows you to monitor other changes to the call's configuration as well. - -Overall, `callParticipants` is a powerful tool that provides you with a lot of control and insight into the call's current state and configuration. By leveraging this parameter effectively, you can create more advanced and robust call applications. - -```dart -for (final user in call.state.value.callParticipants){ - if (user.isDominantSpeaker){ - setState(() => dominantSpeaker = user); - } -} -``` - -The following fields are available on the participant: - -| Attribute | Description| -| --------- | ---------- | -| `userId` | The unique call id of the participant. | -| `role` | The user's role in the call. | -| `custom` | Any custom data added to the user. | -| `trackIdPrefix` | Returns the user's track ID prefix. | -| `publishedTracks` | Returns the participant's tracks. | -| `isSpeaking` | Returns whether the participant is speaking. | -| `isDominantSpeaker` | Returns whether the participant is a dominant speaker. | -| `isPinned` | Returns whether the participant is pinned. | -| `isLocal` | Returns whether the participant is a dominant speaker. | -| `isOnline` | Returns whether the participant is online. | -| `sessionId` | Returns whether the participant is speaking. | -| `connectionQuality` | The participant's connection quality. | -| `joinedAt` | Returns the date when the user joined the call. | -| `audioLevel` | The audio level for the user. | -| `reaction` | The current reaction added by the user. | -| `viewportVisibility` | The user's visibility on the screen. | - -Combining `CallState` and `CallParticipantState` makes building custom UIs and integrations a breeze. -If there is a property or API that is not exposed for your specific use case, feel free to reach out to us. -We are constantly iterating and exposing APIs based on your feedback. - -### Client State - -```dart -// Client state is available in the client object -var clientState = StreamVideo.instance.state; -``` - -| Attribute | Description| -| --------- | ---------- | -| `user` | The user you're currently authenticated as. | -| `connection` | The connection state of Stream Video. | -| `activeCall` | The call you've currently joined. | -| `incomingCall` | Contains the incoming call if `ringing` is set to true. | \ No newline at end of file diff --git a/docusaurus/docs/Flutter/03-core-concepts/04-camera-and-microphone.mdx b/docusaurus/docs/Flutter/03-core-concepts/04-camera-and-microphone.mdx deleted file mode 100644 index 7fe6d16e5..000000000 --- a/docusaurus/docs/Flutter/03-core-concepts/04-camera-and-microphone.mdx +++ /dev/null @@ -1,69 +0,0 @@ ---- -slug: /camera-and-microphone -title: Camera and Microphone -sidebar_position: 4 ---- - -Working with hardware devices can always have some level of complexity to it but the SDK does a lot to abstract the complexities and expose an intuitive interface for querying the connected devices and changing them throughout the call. - -:::note - As a reminder, before attempting to access the user’s connected devices, - please ensure the appropriate permissions are set in both the iOS `plist` file - and Android Manifest. -::: - -### Camera Operations - -Conveniently attached to the `Call` class are a series of methods which can be used to flip the device’s camera, set the camera position, and disable the camera all together. - -```dart -call.flipCamera(); -call.setCameraPosition(CameraPosition.front); -call.setCameraEnabled(enabled: false); -``` - -You can fetch the current camera via the call state: - - ```dart - var camera = call.state.value.videoInputDevice; - ``` - -### Audio Operations - -Similar the Camera API, the `Call` object also includes methods for performing audio actions like disabling the audio devices, configuring the audio input device and audio output device. - -```dart -call.setAudioInputDevice(device); -call.setAudioOutputDevice(device); -call.setMicrophoneEnabled(enabled: true); -``` - -You can fetch the current input and output device via the call state: - -```dart -var microphone = call.state.value.audioInputDevice; -var speaker = call.state.value.audioOutputDevice; -``` - -### Listing Connected Devices - -There may be cases where it becomes necessary to query all of the connected devices or listen to hardware changes such as when the user connects a new microphone or camera to their machine. - -For this, the `RtcMediaDeviceNotifier` can be used. Encapsulated in this class are methods and listeners for interacting with all connected devices. - -```dart -RtcMediaDeviceNotifier.instance.onDeviceChange.listen((devices) { - final audioInputDevice = devices.where((device) => device.kind == RtcMediaDeviceKind.audioInput); - call.setAudioInputDevice(audioInputDevice.first); -}); -``` - -When you need to fetch the list of video and audio devices available on the device, you can use the `RtcMediaDeviceNotifier` class: - -```dart -final videoDevices = RtcMediaDeviceNotifier.instance.audioOutputs(); -final outputDevices = RtcMediaDeviceNotifier.instance.audioInputs(); -final inputDevices = RtcMediaDeviceNotifier.instance.videoInputs(); -``` - -When it comes to audio devices, WebRTC classifies them as two types, `Earpiece` and `Speaker`. These can be used to sort and further filter the devices connected to your app. diff --git a/docusaurus/docs/Flutter/03-core-concepts/05-call-types.mdx b/docusaurus/docs/Flutter/03-core-concepts/05-call-types.mdx deleted file mode 100644 index f7ab7ec67..000000000 --- a/docusaurus/docs/Flutter/03-core-concepts/05-call-types.mdx +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Call Types -slug: /call-types -description: How Call Types control features and permissions -sidebar_position: 5 ---- - -import CallTypesPage from '../../../shared/video/_call-types.mdx'; import WithExternalLinks from '../../../shared/video/_withExternalLinks'; - - \ No newline at end of file diff --git a/docusaurus/docs/Flutter/03-core-concepts/06-querying-calls.mdx b/docusaurus/docs/Flutter/03-core-concepts/06-querying-calls.mdx deleted file mode 100644 index a7a491b76..000000000 --- a/docusaurus/docs/Flutter/03-core-concepts/06-querying-calls.mdx +++ /dev/null @@ -1,91 +0,0 @@ ---- -slug: /querying-calls -title: Querying Calls -sidebar_position: 6 ---- - -For many different use cases, such as video calls, livestreams, or audio rooms, you may want to search and filter calls based on different criteria, such as: - -- Upcoming calls -- Calls that are currently live -- Popular livestreams or audio rooms with a link to the recording. - -To facilitate these, the SDK provides methods which allows users to quickly perform sorting and filtering using the `queryCalls()` method on `StreamVideo`: - -```dart -var calls = StreamVideo.instance.queryCalls(filterConditions: {}); -``` - -### Filtering - -To filter calls, a map containing the fields and conditions must be supplied to `queryCalls` via the `filterConditions` parameter. - -```dart -final result = await video.queryCalls( - filterConditions: { - "custom.flutterAudioRoomCall": true, - }, -); -``` - -In the above example, we filter all calls that contain the custom field `flutterAudioRoomCall`. Other filtering options include call type, members, and start times. - -For instance, to find all livestreams on our application, we can set the `type` filter to `livestream`. - -```dart -final result = await video.queryCalls( - filterConditions: { - "type": 'livestream', - }, -); -``` - -Filter expressions support multiple matching criteria, and it is also possible to combine filters. For more information, please visit the [filter operators guide](https://getstream.io/chat/docs/ios-swift/query_syntax_operators/?language=swift&q=filter). The full list of options that you can filter by is listed in the table below. - -| Option | Description | -| --- | --- | -| type | The call type. Typically default, livestream etc | -| id | The id for this call | -| cid | The cid for this call. IE default:123 | -| created_by_user_id | The user id who created the call | -| created_at | When the call was created | -| updated_at | When the call was updated | -| starts_at | When the call starts at | -| ended_at | When the call ended | -| backstage | If the call is in backstage mode or not | -| members | Check if you are a member of this call | -| custom | You can query custom data using the "custom.myfield" syntax | - -### Sorting - -Similar to filtering, the SDK offers robust support for sorting, enabling sorting on the following fields: - -- `starts_at` -- `created_at` -- `updated_at` -- `ended_at` -- `type` -- `id` -- `cid` - -To add a sort, it is simple as specifying a list of sorts to the `queryCalls` function: - -```dart -final result = await video.queryCalls( - // ... - sorts: [ - SortParamRequest(field: 'starts_at', direction: -1), - ], -); -``` - -The `queryCalls` function can take multiple sort parameters, which can be combined with filtering to give you powerful control over the data in your application. - -### Watching calls -​ -If you specify `watch` parameter as `true`, the SDK will create a subscription to the call data on the server and you'll be able to receive updates in real-time. - -The server will send updates to the client when the call data changes (for example, members are updated, a call session has started, etc...). This is useful for showing a live preview of who is in the call or building a call dashboard. - -You can listen to call events via the `StreamVideo.instance.events` stream. - diff --git a/docusaurus/docs/Flutter/03-core-concepts/07-permission-and-moderation.mdx b/docusaurus/docs/Flutter/03-core-concepts/07-permission-and-moderation.mdx deleted file mode 100644 index 024d732ad..000000000 --- a/docusaurus/docs/Flutter/03-core-concepts/07-permission-and-moderation.mdx +++ /dev/null @@ -1,105 +0,0 @@ ---- -slug: /permission-and-moderation -title: Permission and Moderation -sidebar_position: 7 ---- - -In some types of calls, there's a requirement to moderate the behaviour of the participants. - -Examples include muting a participant, or ending the call for everyone. Those capabilities are usually reserved for the hosts of the call (users with elevated capabilities). They usually have additional moderation controls in their UI, that allow them to achieve these actions. - -The Flutter SDK for Stream Video has support for such capabilities, with the usage of the permissions features for the `Call` class. - -### Current Permissions - -To check if a user has certain permissions, such as transmitting audio, video, or screen sharing, you can use the `hasPermission` method on the `Call` class: - -``` -final canScreenShare = call.hasPermission(CallPermission.screenshare); -``` - -### Requesting and Granting Permissions - -If a user does not have permission for an action, it can be requested by calling `requestPermissions()` on the current `Call` object. - -This method accepts a list of `CallPermission` allowing for multiple permission requests to be batched into a single call: - -```dart -call.requestPermissions([CallPermission.screenshare, CallPermission.sendVideo]); -``` - -As a call admin, you can grant permission to other users by calling `call.grantPermissions` along with the user’s `id` and the list of permissions you would like to grant: - -```dart -call.grantPermissions(userId: 'nash', permissions: [CallPermission.screenshare, CallPermission.sendVideo]); -``` - -During a call, it is advised to set up a handler to listen and react to permission requests as they arrive. This can be done by passing a callback function to the `onPermissionRequest` property present on the `Call` object: - -```dart -@override -void initState() { - super.initState(); - widget.call.onPermissionRequest = (CoordinatorCallPermissionRequestEvent request) { - // TODO Handle Permission requests - // For example: widget.call.grantPermissions(userId: request.user.id, permissions: request.permissions); - }; -} -``` - -The `CoordinatorCallPermissionRequestEvent` includes the following attributes which can be used to either grant or reject permission requests: - -- Call Cid -- Created At -- Permissions -- User - -### Moderation Capabilities - -As with all calls, there may be times when user permissions need to be revoked, or the user needs to be banned, muted, or subjected to other actions to limit their interaction. - -To facilitate these requests, the SDK provides several methods for limiting user interaction during the call lifecycle. - -**Revoke Permissions** - -Similar to its sister method `grantPermissions`, the `revokePermissions` method exists on the current `Call` object. It enables users to easily remove permissions assigned to a specific user by providing their user ID and the list of permissions to be revoked.. - -```dart -call.revokePermissions(userId: 'nash', permissions: [CallPermission.screenshare, CallPermission.sendVideo]); -``` - -**Mute Users** - -To disable the audio tracks of all users on a call or a specific user in a call, the `muteOthers` and `muteUser` functions can be called, respectively. - -```dart -call.muteAllUsers(); -``` - -```dart -call.muteUsers(userIds: ['thierry']); -``` - -:::note -In the above example, we are only muting a single user. However, `muteUsers` does allow us to mute multiple users since it accepts a list of user IDs. -::: - -**Blocking Members** - -Blocking and unblocking users can be done by calling `blockUser` or `unblockUser` on the current `Call` object. - -```dart -call.blockUser('deven'); - -call.unblockUser('deven'); -``` - -**Ending the Call** - -As a host, you are able to end the current call for everyone using the `call.end` method. - -```dart -await call.end(); -``` - -To silently leave a call, the `disconnect` method can be used in place of the `end` method. diff --git a/docusaurus/docs/Flutter/03-core-concepts/08-call-statistics.mdx b/docusaurus/docs/Flutter/03-core-concepts/08-call-statistics.mdx deleted file mode 100644 index 3b96c91cf..000000000 --- a/docusaurus/docs/Flutter/03-core-concepts/08-call-statistics.mdx +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Call Statistics -slug: /call-statistics -description: How to listen and leverage call statistics -sidebar_position: 12 ---- - -There are two sources of statistics you can use to monitor the performance of your calls: -- `Call.stats` stream that provides real-time webRTC statistics -- `CallState` properties that contain some of the webRTC statistics processed and more useful for display purposes - -## Stats stream - -If you want to tap in directly into the stream of webRTC stats you can do this with `stats` stream inside `Call` object. It provides a stream of [`CallStats`](https://github.com/GetStream/stream-video-flutter/blob/main/packages/stream_video/lib/src/models/call_stats.dart) objects for publisher and subscriber connections. -We provide those statistics in three ways for ease of use: - -* `raw` - Raw stats as they come from WebRTC. -* `printable` - Representation of the stats that can be easily printed to the console or as a block of text. -* `stats` - WebRTC stats but in a structured form. - -## CallState properties - -You can also access more processed data with useful information about the call. This data is available in [`CallState`](https://github.com/GetStream/stream-video-flutter/blob/main/packages/stream_video/lib/src/call_state.dart) object. Here are some of the properties that you can use: - -`publisherStats` and `subscriberStats` - objects that contain the following data: - -* `latency` - The time it takes to deliver the data between the server and the app. -* `jitterInMs` - The variation in the delay of receiving packets of data over a network. -* `bitrateKbps` - The rate at which data is transmitted from the app to the server (publisher) or from the server to the app (subscriber). - -`localStats` - An object that contains the following data: - -* `sfu` - The server to which the device is connected. -* `sdkVersion` - The version of the Stream SDK. -* `webRtcVersion` - The version of WebRTC. - -`latencyHistory` - Array of latency values for the last 10 seconds. - -## Example usage - -You can check the example of the stats screen in our [demo app](https://github.com/GetStream/stream-video-flutter/blob/main/dogfooding/lib/screens/call_stats_screen.dart) - -![Sample Call Stats screen](../assets/core_concepts/stats_screen.jpeg) - diff --git a/docusaurus/docs/Flutter/03-core-concepts/09-call-events.mdx b/docusaurus/docs/Flutter/03-core-concepts/09-call-events.mdx deleted file mode 100644 index 93fab0b43..000000000 --- a/docusaurus/docs/Flutter/03-core-concepts/09-call-events.mdx +++ /dev/null @@ -1,71 +0,0 @@ ---- -title: Call Events -slug: /call-events -description: How to listen and leverage call events -sidebar_position: 11 ---- - -There are multiple events that you can listen to during a call. You can use them to update the UI, show notifications, or log the call events. You can listen to them via `callEvents` stream in the `Call` object. - -Here are some of the events you can listen to: - - -| Call Event | Description | -| --------------------------------------------- | ----------------------------------------------------- | -| **General Call Events** | | -| `StreamCallCreatedEvent` | Triggered when a call is created. | -| `StreamCallJoinedEvent` | Triggered when a user joins a call. | -| `StreamCallEndedEvent` | Triggered when the call ends. | -| `StreamCallUpdatedEvent` | Triggered when the call metadata are updated. | -| **Participant Events** | | -| `StreamCallParticipantJoinedEvent` | Triggered when a participant joins the call. | -| `StreamCallParticipantLeftEvent` | Triggered when a participant leaves the call. | -| `StreamCallDominantSpeakerChangedEvent` | Triggered when the dominant speaker changes. | -| **Quality and Control Events** | | -| `StreamCallConnectionQualityChangedEvent` | Triggered when connection quality changes for participants. | -| `StreamCallAudioLevelChangedEvent` | Triggered when audio levels change for participants. | -| `StreamCallPermissionRequestEvent` | Triggered when there is a permission request for a call. | -| `StreamCallPermissionsUpdatedEvent` | Triggered when permissions for a call are updated. | -| **Call Ringing Events** | | -| `StreamCallRingingEvent` | Triggered when the call is ringing. | -| `StreamCallAcceptedEvent` | Triggered when the call is accepted. | -| `StreamCallRejectedEvent` | Triggered when the call is rejected. | -| **Media Events** | | -| `StreamCallRecordingStartedEvent` | Triggered when recording starts for a call. | -| `StreamCallRecordingStoppedEvent` | Triggered when recording stops for a call. | -| `StreamCallBroadcastingStartedEvent` | Triggered when broadcasting starts for a call. | -| `StreamCallBroadcastingStoppedEvent` | Triggered when broadcasting stops for a call. | -| **Session Events** | | -| `StreamCallSessionStartedEvent` | Triggered when a new session starts for a call. | -| `StreamCallSessionEndedEvent` | Triggered when a session ends for a call. | -| `StreamCallSessionParticipantJoinedEvent` | Triggered when a participant joins the call session. | -| `StreamCallSessionParticipantLeftEvent` | Triggered when a participant leaves the call session. | -| **Other Events** | | -| `StreamCallUserBlockedEvent` | Triggered when a user is blocked in a call. | -| `StreamCallUserUnblockedEvent` | Triggered when a user is unblocked in a call. | -| `StreamCallReactionEvent` | Triggered when someone sends a reaction during a call.| - -## Custom event - -Stream Video also supports custom events. This is a real-time layer that you can broadcast your own events to. - -### Sending custom events - -You can use the `sendCustomEvent` method of the `Call` instance to send custom events: - -```dart -call.sendCustomEvent( - eventType: 'my-custom-event', - custom: { - 'key': 'value', - }, -); -``` - -### Receiving custom events -​ -You can listen to custom events by listening to the `StreamCallCustomEvent` event via the same `callEvents` stream: - -```dart -call.callEvents.on((event) { }); -``` \ No newline at end of file diff --git a/docusaurus/docs/Flutter/03-core-concepts/10-initial-call-configuration.mdx b/docusaurus/docs/Flutter/03-core-concepts/10-initial-call-configuration.mdx deleted file mode 100644 index 591ead56e..000000000 --- a/docusaurus/docs/Flutter/03-core-concepts/10-initial-call-configuration.mdx +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: Initial call configuration -slug: /initial-call-configuration -description: How to configure the initial call setup -sidebar_position: 10 ---- - -There are two ways to configure the initial call setup: -* Using the Stream Dashboard to setup the initial configuration per call type -* Passing the initial configuration in by `CallConnectOptions` parameter - -### Stream Dashboard - -You can configure the initial call setup using the Stream Dashboard. This is useful when you want to set up the initial configuration for a specific call type. -Find the call type you want to configure on the list of call types: https://dashboard.getstream.io/app/{YOUR-APP-ID}/video/call-types. Then under Video, Audio and Advanced settings sections you can set things like: - -* Turn camera on/off by default -* Turn microphone on/off by default -* Set default camera facing -* Set default audio output device - -![Advanced settings dashboard](../assets/core_concepts/advanced-settings.png) - -### CallConnectOptions parameter -​ -Using the `CallConnectOptions` class you can configure the initial call setup programmatically. It provides the following options: - -* Enabling or disabling the camera -* Enabling or disabling the microphone -* Enabling or disabling the screen sharing -* Setting the camera facing mode -* Setting the audio output device -* Setting the audio input device - -You can provide this class as a parameter when joining a call: - -```dart - final call = client.makeCall(callType: StreamCallType.defaultType(), id: '345'); - await call.join(connectOptions: connectOptions); -``` - -Or by passing it to the `StreamCallContainer` widget - -```dart -StreamCallContainer( - call: widget.call, - callConnectOptions: connectOptions, - ... -); -``` - -You can access current options by calling `call.connectOptions` on the `Call` object. - -```dart - final call = client.makeCall(callType: StreamCallType.defaultType(), id: '345'); - await call.getOrCreate(); - final callOptions = call.connectOptions; -``` - -:::info - When `getOrCreate` method is called, the default options will be created based on the Stream Dashboard settings. - You can then leverage the `call.connectOptions` to modify the default settings and pass them to the `join` method at the end. -::: - -:::note - `call.connectOptions` also has a setter but it should be used carefully. Depending on the moment in the call lifecycle, it might be overwritten by default configuration or it might be too late to apply the changes. -::: \ No newline at end of file diff --git a/docusaurus/docs/Flutter/03-core-concepts/11-reactions.mdx b/docusaurus/docs/Flutter/03-core-concepts/11-reactions.mdx deleted file mode 100644 index ce89df8c2..000000000 --- a/docusaurus/docs/Flutter/03-core-concepts/11-reactions.mdx +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: Reactions -slug: /reactions -description: How to use reactions during the call -sidebar_position: 8 ---- - -## Reactions -​ -Reactions in video calling enable participants to express emotions and non-verbal cues without interrupting the flow of conversation. They also help create a more interactive and responsive virtual meeting environment. - -It is easy to create reactions with Stream Video's Flutter SDK. - -```dart -await call.sendReaction(reactionType: 'fireworks'); -``` - -You can also add custom data to the reaction and specify a specific emoji: - -```dart -await call.sendReaction( - reactionType: 'raise-hand', - emojiCode: ':smile:', - custom: {'mycustomfield': 'mycustomvalue'}, - ); -``` - -Refer to the [cookbook](https://getstream.io/video/docs/flutter/ui-cookbook/reactions/) for information on built-in reaction components and customization. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/03-core-concepts/12-participants-sorting.mdx b/docusaurus/docs/Flutter/03-core-concepts/12-participants-sorting.mdx deleted file mode 100644 index 0d90c6f2a..000000000 --- a/docusaurus/docs/Flutter/03-core-concepts/12-participants-sorting.mdx +++ /dev/null @@ -1,169 +0,0 @@ ---- -slug: /participant-sorting -title: Participant Sorting -sidebar_position: 9 ---- - -The Participant Sorting API is a powerful tool built on top of the internal `Comparator` API, providing developers with the ability to sort participants in various scenarios. This API offers common comparators and built-in presets that can be easily customized or used out-of-the-box, making participant sorting a seamless experience. - -When dealing with real-time communication applications, it is often necessary to sort participants based on specific criteria. Whether you need to adjust the sorting in existing view layouts or define new sorting presets, the Participant Sorting API is here to simplify the process. - -By utilizing the `Comparator` API and the provided built-in comparators and presets, developers can effortlessly sort participants according to their requirements. - -## `Comparator` API overview -​ - -The `Comparator` API serves as the foundation for the Participant Sorting API. It defines the function type `Comparator`, which takes two arguments a and b of type T and returns -1, 0, or 1, depending on the comparison between the two values. This allows developers to create custom comparators tailored to their specific requirements. - -This API can be seamlessly used with Dart's List.sort method to sort any type of data. - -```dart -class Participant { - Participant(this.id, this.name, this.age); - - final int id; - final String name; - final int age; -} - -// Comparator that sorts by name in ascending order -int byName(Participant a, Participant b) { - return a.name.compareTo(b.name); -} - -// Comparator that sorts by id in ascending order -int byId(Participant a, Participant b) { - return a.id.compareTo(b.id); -} - -// Comparator that sorts by age in ascending order -int byAge(Participant a, Participant b) { - return a.age.compareTo(b.age); -} - -// Creates a new comparator that sorts by name in descending order -Comparator byNameDescending = (a, b) => byName(b, a); - -// Conditional comparator for sorting by age if enabled -Comparator byAgeIfEnabled(bool isSortByAgeEnabled) { - return (a, b) => isSortByAgeEnabled ? byAge(b, a) : 0; -} - -// Combines multiple comparators into one -Comparator combineComparators(List> comparators) { - return (a, b) { - for (final comparator in comparators) { - final result = comparator(a, b); - if (result != 0) return result; - } - return 0; - }; -} - -// Sorting criteria combining multiple comparators -Comparator sortingCriteria = combineComparators([ - byNameDescending, - byAgeIfEnabled(true), // You can toggle this flag for conditional sorting - byId, -]); - -void main() { - // Example participants - final p1 = Participant(2, 'Alice', 25); - final p2 = Participant(1, 'Bob', 30); - final p3 = Participant(3, 'Charlie', 22); - - // Participants array - final participants = [p1, p2, p3]; - - // Sorting the array based on the defined criteria - participants.sort(sortingCriteria); - - // Output sorted participants - for (final p in participants) { - print('${p.name} (${p.id}) - Age: ${p.age}'); - } -} -``` - -## Built-in common comparators -​ -The Participant Sorting API provides a set of common comparators that cover common sorting scenarios. These comparators are specifically designed for participant sorting and offer convenience when defining sorting criteria. - -The built-in common comparators include: - -* `dominantSpeaker`: Sorts participants based on their dominance in the call. -* `speaking`: Sorts participants based on whether they are currently speaking. -* `screenSharing`: Sorts participants based on whether they are currently screen sharing. -* `publishingVideo`: Sorts participants based on whether they are currently publishing video. -* `publishingAudio`: Sorts participants based on whether they are currently publishing audio. -* `pinned`: Sorts participants based on whether they are pinned in the user interface. -* `reactionType(type)`: Sorts participants based on the type of reaction they have. -* `byRole(...roles)`: Sorts participants based on their assigned role. -* `byName`: Sorts participants based on their names. - -All of these comparators are available in the `stream_video` package and can be imported as follows: - -```dart -import 'package:stream_video/stream_video.dart'; -``` - -These built-in comparators serve as a starting point for sorting participants and can be used individually or combined to create more complex sorting criteria. - -## Built-in sorting presets -​ -To further simplify participant sorting, the Participant Sorting API offers built-in presets. These presets are pre-configured sorting criteria linked to specific call types, reducing the effort required to define sorting rules. - -The following presets are available: - -* `regular`: The default sorting preset applicable to general call scenarios. -* `speaker`: A preset specifically designed for the 'default' call type, optimizing participant sorting for speaker layout view. -* `livestreamOrAudioRoom`: A preset tailored for the 'livestream' and 'audio_room' call types, ensuring optimal participant sorting in livestream or audio room scenarios. - -All of these presets are available in the `stream_video` package and can be imported as follows: - -```dart -import 'package:stream_video/stream_video.dart'; -``` - -## Sorting customization - -By default participant sorting is set depending on the participants layout mode set in the `StreamCallContent` widget: - -```dart -Comparator get sorting { - switch (this) { - case ParticipantLayoutMode.grid: - return CallParticipantSortingPresets.regular; - case ParticipantLayoutMode.spotlight: - return CallParticipantSortingPresets.speaker; - case ParticipantLayoutMode.pictureInPicture: - return CallParticipantSortingPresets.speaker; - } -} -``` - -If you want to customize it, providing different preset or even your own custom sorting comparator, you can do it by providing `sort` parameter to `StreamCallParticipants` widget and using it in the `StreamCallContent's` `callParticipantsBuilder`: - -```dart -StreamCallContainer( - ..., - callContentBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallContent( - call: call, - callState: callState, - callParticipantsBuilder: (context, call, callState) { - return StreamCallParticipants( - call: call, - participants: callState.callParticipants, - sort: screenSharing, - ); - }, - ); - }, -); -``` \ No newline at end of file diff --git a/docusaurus/docs/Flutter/03-core-concepts/_category_.json b/docusaurus/docs/Flutter/03-core-concepts/_category_.json deleted file mode 100644 index 18cd6792f..000000000 --- a/docusaurus/docs/Flutter/03-core-concepts/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Core Concepts" -} diff --git a/docusaurus/docs/Flutter/04-ui/01-overview.mdx b/docusaurus/docs/Flutter/04-ui/01-overview.mdx deleted file mode 100644 index bb290a059..000000000 --- a/docusaurus/docs/Flutter/04-ui/01-overview.mdx +++ /dev/null @@ -1,29 +0,0 @@ ---- -slug: /ui-components-overview -title: UI Components Overview ---- - -### Introduction - -The Stream Video Flutter SDK provides UI components to facilitate the quick integration of voice, video, and streaming use cases in your applications. - -As a developer building with Stream, you can either use our out-of-the-box solution, inclusive of theming, views, and state handling, or completely build your own UI while reusing our lower-level components where you see fit. - -### Component Overview - -| Name | ClassName | Overview | -| ----------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Video Renderer | StreamVideoRenderer | Widget that renders a single video track for a call participant. StreamVideoRenderer exposes callbacks for handling size changes, video fit types, and more! | -| Call Container | StreamCallContainer | Call Container automatically subscribes to call events and displays the appropriate UI based on the various call states. For example, Call Container will automatically display an incoming call screen when a ringing call is detected and update the UI to display the call contents if the user chooses to answer. | -| Incoming Call | StreamIncomingCallContent | Displays a ringing interface to the current user when an incoming call is detected. | -| Outgoing Call | StreamOutgoingCallContent | Represents the UI of a call when the current user rings another user. | -| Call Content | StreamCallContent | Represents the UI of an active call. This Widget displays the participants, controls, and call app bar by default. | -| Call Controls | StreamCallControls | These represent a set of options the user can interact with to control various aspects of the call such as toggling the microphone, camera, etc. For convenience, we provide a `withDefaultOptions` constructor. | -| Call Participants | StreamCallParticipants | StreamCallParticipants renders the participants on a call and adjusts itself based on the number of participants, screen-sharing, grid type, etc. | -| Lobby View | StreamLobbyView | A widget that can be shown before a user joins a meeting or call. It allows the user to configure their microphone, camera, and output device state before joining a call. | - -These are just a few of our offered components. Each component has many lower-level widgets which can be used independently to create custom UIs and experiences for your application. - -Please continue reading on or select a component directly to learn more about how it can be used and customized to fit the needs of your application. - -If there is a widget or component you would like to see added to the library, please feel free to contact us, we are always open to feedback and constantly looking to add more widgets. diff --git a/docusaurus/docs/Flutter/04-ui/02-call-container.mdx b/docusaurus/docs/Flutter/04-ui/02-call-container.mdx deleted file mode 100644 index 341773e88..000000000 --- a/docusaurus/docs/Flutter/04-ui/02-call-container.mdx +++ /dev/null @@ -1,58 +0,0 @@ ---- -slug: /call-container -title: Call Container ---- - -Similar to Flutter’s out-of-the-box `Container` widget, `StreamCallContainer` serves as a convenient widget for handling everything related to video and calling. -It is the easiest way to setup a screen that shows incoming, outgoing and active call screens which contain the current participants video feeds and the call controls. - -`CallContainer` sets up the following functionality by connecting multiple components: - -* `StreamOutgoingCallContent`: When the user is calling other people. Shows other participants avatars and controls for switching audio/video and canceling the call. -* `StreamIncomingCallContent`: When the user is being called by another person. Shows the incoming call screen. -* `StreamCallContent`: When the user is in an active call. - -In this section we will cover this higher level component which enables you to quickly implement a video calling app. - -![Incoming call screen](../assets/ui_component_assets/incoming_call_screen.png) - -### Customizing Call Container - -```dart -const StreamCallContainer({ - super.key, - required this.call, - this.callConnectOptions, - this.onBackPressed, - this.onLeaveCallTap, - this.onAcceptCallTap, - this.onDeclineCallTap, - this.onCancelCallTap, - this.incomingCallBuilder, - this.outgoingCallBuilder, - this.callContentBuilder, - this.pictureInPictureConfiguration = const PictureInPictureConfiguration(), -}); -``` - -Developers can easily respond to user actions, such as accepting or declining a call, by using exposed callbacks and builders. - -To replace default screens, such as the one displayed when an incoming call is detected, developers can use one of the many optional builders available. - -```dart - @override - Widget build(BuildContext context) { - return Scaffold( - body: StreamCallContainer( - call: widget.call, - incomingCallBuilder: (context, call, callState) { - return CustomIncomingCallScreen(call: call, state: callState); - }, - ), - ); - } -``` - -All the `builders` exposed by `StreamCallContainer` provide users with an ongoing `Call` object and the associated `CallState`. These can be used to subscribe to changes and display different UI options depending on the events. - -If your use case does not require ringing, incoming, or outgoing capabilities similar to Google Meet, then our `CallScreen` widget may be a better option. Keep reading to learn how to use it in your application. diff --git a/docusaurus/docs/Flutter/04-ui/03-video-render.mdx b/docusaurus/docs/Flutter/04-ui/03-video-render.mdx deleted file mode 100644 index b58ec1d31..000000000 --- a/docusaurus/docs/Flutter/04-ui/03-video-render.mdx +++ /dev/null @@ -1,82 +0,0 @@ ---- -slug: /video-render -title: Video Renderer ---- - -One of the primary low-level widgets we offer is `StreamVideoRenderer`. As the name suggests, this widget is specifically designed to render the video track of a call participant. It also exposes callbacks that can be utilized to handle sizing changes, placeholder content, and other related functionalities. - -However, since `StreamVideoRenderer` is relatively basic, we have also introduced `StreamCallParticipant` as an extended version. It adds several extra features on top of `StreamVideoRenderer`, such as connection quality indicators, microphone indicators, and more. - -Since the SDK is designed to be modular and customizable, developers can choose whether they want to use the raw renderer or the participant widget. - -:::tip -When in doubt, we recommend starting with `StreamCallParticipant` unless there is an explicit reason not to. -::: - -### Customizing `StreamCallParticipant` - -```dart - const StreamCallParticipant({ - super.key, - required this.call, - required this.participant, - this.videoFit, - this.backgroundColor, - this.borderRadius, - this.userAvatarTheme, - this.showSpeakerBorder, - this.speakerBorderThickness, - this.speakerBorderColor, - this.showParticipantLabel, - this.participantLabelTextStyle, - this.participantLabelAlignment, - this.audioLevelIndicatorColor, - this.enabledMicrophoneColor, - this.disabledMicrophoneColor, - this.showConnectionQualityIndicator, - this.connectionLevelActiveColor, - this.connectionLevelInactiveColor, - this.connectionLevelAlignment, - this.videoPlaceholderBuilder, - this.videoRendererBuilder, - this.onSizeChanged, - }); -``` - -Call Participant allows you to customize everything from the background color and border radius to setting placeholder content and customizing the audio level indicators. - -To use the widget, you need to supply two arguments: the current `call` and `participant` to render. Both of these parameters can be fetched from either `activeCall` or `callState`. - -```dart - StreamCallContent( - call: call, - callState: callState, - callParticipantsBuilder: (context, call, callState) { - return StreamCallParticipant( - call: call, - participant: callState.localParticipant!, - ); - }, - ); -``` - -### Using `StreamVideoRenderer` directly: - -```dart - StreamCallContent( - call: call, - callState: callState, - callParticipantsBuilder: (context, call, callState) { - return StreamVideoRenderer( - call: call, - participant: callState.localParticipant!, - videoTrackType: SfuTrackType.screenShare, - videoFit: VideoFit.contain, - ); - }, - ); -``` - -Video Render is the lowest level component for displaying a participant's video in Flutter. Unlike `StreamCallParticipant`, the options exposed by `StreamVideoRenderer` are minimal and focuses more on video fit and layout, determining which track types to display, and providing callbacks for handling changes to the video rendering. - -Both `StreamVideoRenderer` and `StreamCallParticipant` can be used as part of other components, such as `StreamCallContent`, or as standalone widgets in your application, as long as the `call` and `participant` parameters are supplied. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/04-ui/04-call-content.mdx b/docusaurus/docs/Flutter/04-ui/04-call-content.mdx deleted file mode 100644 index 998f6efcd..000000000 --- a/docusaurus/docs/Flutter/04-ui/04-call-content.mdx +++ /dev/null @@ -1,111 +0,0 @@ ---- -slug: /call-content -title: Call Content ---- - - -Similar to `StreamCallContainer`, `CallContent` allows for the display of participants on a call, while providing options for customization and custom UI. The widget manages the display of video rendering and call controls. - -However, unlike `StreamCallContainer`, the sole responsibility of `StreamCallContent` is to render the call participants and controls. `StreamCallContent` does not monitor or respond to call lifecycle events, such as incoming and outgoing calls. - -```dart - const StreamCallContent({ - super.key, - required this.call, - required this.callState, - this.onBackPressed, - this.onLeaveCallTap, - this.callAppBarBuilder, - this.overlayAppBarBuilder, - this.callParticipantsBuilder, - this.callControlsBuilder, - this.layoutMode = ParticipantLayoutMode.grid, - this.enablePictureInPicture = false, - this.callPictureInPictureBuilder, - }); -``` - -To customize `StreamCallContent`, one of the following builders can be used: - -- callControlsBuilder -- callParticipantsBuilder -- overlayAppBarBuilder -- callAppBarBuilder - -```dart -class CallScreen extends StatefulWidget { - const CallScreen({ - super.key, - required this.call, - required this.chatChannel, - this.callConnectOptions = const CallConnectOptions(), - }); - - final Call call; - final CallConnectOptions callConnectOptions; - final Channel chatChannel; - - @override - State createState() => _CallScreenState(); -} - -class _CallScreenState extends State { - void showChatDialog(BuildContext context) { - showBottomSheet( - context: context, - backgroundColor: const Color(0xFF101418), - builder: (_) { - return const FractionallySizedBox( - heightFactor: 0.8, - child: Material( - child: Center( - child: Text('TODO Chat UI'), - ), - ), - ); - }, - ); - } - -@override - Widget build(BuildContext context) { - return Scaffold( - body: StreamCallContent( - call: widget.call, - callState: widget.call.state.value, - callControlsBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - final localParticipant = callState.localParticipant!; - return StreamCallControls( - options: [ - CallControlOption( - icon: const Icon(Icons.chat_outlined), - onPressed: () => showChatDialog(context), - ), - ToggleMicrophoneOption( - call: call, - localParticipant: localParticipant, - ), - ToggleCameraOption( - call: call, - localParticipant: localParticipant, - ), - LeaveCallOption( - call: call, - onLeaveCallTap: () => call.leave(), - ), - ], - ); - }, - ), - ); - } -} -``` - -In the above example, we’re overriding the default call controls using `callControlsBuilder` to add a button to display an in-app dialog for chat. - -To learn more how call controls work in Stream Video, continue reading to the next chapter 😃. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/04-ui/05-call-controls.mdx b/docusaurus/docs/Flutter/04-ui/05-call-controls.mdx deleted file mode 100644 index f92a85780..000000000 --- a/docusaurus/docs/Flutter/04-ui/05-call-controls.mdx +++ /dev/null @@ -1,66 +0,0 @@ ---- -slug: /call-controls -title: Call Controls ---- - - -By default, `StreamCallContent` renders controls for the user to interact with, such as leaving a call, controlling their microphone and camera, etc. - -However, in cases where developers want to override these controls, they can use the `StreamCallControls` class. - -If left unmodified, Stream Call Content uses the `.withDefaultOptions` constructor. - -```dart -List defaultCallControlOptions({ - required Call call, - required CallParticipantState localParticipant, - VoidCallback? onLeaveCallTap, -}) { - return [ - ToggleSpeakerphoneOption(call: call), - ToggleCameraOption(call: call, localParticipant: localParticipant), - ToggleMicrophoneOption(call: call, localParticipant: localParticipant), - FlipCameraOption(call: call, localParticipant: localParticipant), - LeaveCallOption(call: call, onLeaveCallTap: onLeaveCallTap), - ]; -} -``` - -Developers can supply a list of custom options for their call using the default constructor. It's common to use a combination of both Stream default options and custom options. For example, you can use Stream's default buttons for leaving the call, controlling the microphone, and camera, while including a custom option to perform an activity specific to your application, such as sending a custom event or reaction. - -```dart -StreamCallContent( - call: call, - callState: callState, - callControlsBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - final localParticipant = callState.localParticipant!; - return StreamCallControls( - options: [ - // Custom call option toggles the chat while on a call. - CallControlOption( - icon: const Icon(Icons.chat_outlined), - onPressed: () => showChatDialog(context), - ), - ToggleMicrophoneOption( - call: call, - localParticipant: localParticipant, - ), - ToggleCameraOption( - call: call, - localParticipant: localParticipant, - ), - LeaveCallOption( - call: call, - onLeaveCallTap: () => call.leave(), - ), - ], - ); - }, -); -``` - -As an example, the above snippet demonstrates how a custom `CallControlOption` can be used to display a chat dialog while a user is on a call. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/04-ui/06-video-theme.mdx b/docusaurus/docs/Flutter/04-ui/06-video-theme.mdx deleted file mode 100644 index 3a9ee00ba..000000000 --- a/docusaurus/docs/Flutter/04-ui/06-video-theme.mdx +++ /dev/null @@ -1,81 +0,0 @@ ---- -slug: /video-theme -title: Video Theme ---- - - -Understanding How To Customize Widgets Using `StreamVideoTheme` - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_video_flutter/latest/stream_video_flutter/StreamVideoTheme-class.html) - -### Background - -Stream's UI SDK makes it easy for you to add custom styles and attributes to our widgets. - -Through the use of `StreamVideoTheme`, you can extensively customize various elements of our UI widgets by applying modifications using `StreamVideoTheme.copyWith`. - -`StreamVideoTheme` is a theme extension, meaning that it can be applied to your application's theme using [`ThemeData.extensions`](https://api.flutter.dev/flutter/material/ThemeExtension-class.html): -```dart -ThemeData(extensions: >[StreamVideoTheme.dark()]) -``` - -:::note -In case of `StreamVideoTheme` instance is not passed at the root layer either `StreamVideoTheme._kLightFallbackTheme` or `StreamVideoTheme._kDarkFallbackTheme` will be used as a fallback based on `ThemeData.brightness` value. -::: - -### A closer look at StreamVideoTheme - -Looking at the constructor for `StreamVideoTheme`, we can see the full list of properties and widgets available for customization. - -Some high-level properties such as `textTheme` or `colorTheme` can be set application-wide directly from this class. -In contrast, larger components such as `StreamCallParticipant`, `StreamLobbyView`, etc. have been addressed with smaller theme objects. - -```dart - factory StreamVideoTheme({ - required Brightness brightness, - StreamTextTheme? textTheme, - StreamColorTheme? colorTheme, - StreamCallContentThemeData? callContentTheme, - StreamCallControlsThemeData? callControlsTheme, - StreamUserAvatarThemeData? userAvatarTheme, - StreamLobbyViewThemeData? lobbyViewTheme, - StreamCallParticipantThemeData? callParticipantTheme, - StreamLocalVideoThemeData? localVideoTheme, - StreamIncomingOutgoingCallThemeData? incomingCallTheme, - StreamIncomingOutgoingCallThemeData? outgoingCallTheme, - StreamLivestreamThemeData? livestreamTheme, - }); -``` - -### Stream Video Theme in use - -Let's take a look at customizing widgets using `StreamVideoTheme`. -In the example below, we're changing the default `accentPrimary` color to `lightBlue` and overriding the typography and colors of `StreamCallParticipant` labels for the `Dark` theme. - -```dart -bool isLightTheme = false; - -final darkAppTheme = StreamVideoTheme.dark(); -final lightAppTheme = StreamVideoTheme.light(); - -MaterialApp( - theme: ThemeData( - extensions: >[lightAppTheme], - ), - darkTheme: ThemeData( - extensions: >[ - darkAppTheme.copyWith( - colorTheme: darkAppTheme.colorTheme.copyWith( - accentPrimary: Colors.lightBlue, - ), - callParticipantTheme: darkAppTheme.callParticipantTheme.copyWith( - participantLabelTextStyle: const TextStyle( - color: Colors.white, - ), - ), - ), - ], - ), - themeMode: isLightTheme ? ThemeMode.light : ThemeMode.dark, - ... -); \ No newline at end of file diff --git a/docusaurus/docs/Flutter/04-ui/07-call-participants.mdx b/docusaurus/docs/Flutter/04-ui/07-call-participants.mdx deleted file mode 100644 index 6f8a88b1a..000000000 --- a/docusaurus/docs/Flutter/04-ui/07-call-participants.mdx +++ /dev/null @@ -1,184 +0,0 @@ ---- -slug: /call-participants -title: Call Participants ---- - -Often in a video call, an app needs the ability to arrange and resize the video feeds of different -participants on the screen to suit design needs. Customizing participant layouts is a simple but -effective way to improve the quality and experience of video calls. It can help to improve focus and engagement, -highlight key speakers or presenters, and accommodate the different needs of participants. - -By default, the Flutter SDK for Stream Video displays a grid of participants in a call. - -To create your own layout for the user participants instead, use the `callParticipantsBuilder` parameter -of the `StreamCallContent` widget. - -The default widget used is the `StreamCallParticipants` widget: - -```dart -StreamCallContent( - call: call, - callState: callState, - callParticipantsBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallParticipants( - call: call, - participants: callState.callParticipants, - ); - }, -); -``` - -:::note -As a reminder, the `StreamCallContent` widget above can be supplied to the `callContentBuilder` parameter -of the `StreamCallContainer` widget which manages most of the UI components related to a call. -::: - -If you need a fully custom widget, you can supply your own widget in place of `StreamCallParticipants`. - -However, the `StreamCallParticipants` widget also allows you to customise quite a few things. - -## Change only participant grid elements - -To change all participant video elements, you can use the `callParticipantsBuilder` parameter. This will -be applied to all user video elements: - -```dart -StreamCallContent( - call: call, - callState: callState, - callParticipantsBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallParticipants( - call: call, - participants: callState.callParticipants, - callParticipantBuilder: ( - BuildContext context, - Call call, - CallParticipantState callState, - ) { - // Build call participant video - }, - ); - }, -); -``` - -## Change local participant video - -To only change the local participant video, use the `localVideoParticipantBuilder` parameter which only -changes the local participant video stream: - -```dart -StreamCallContent( - call: call, - callState: callState, - callParticipantsBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallParticipants( - call: call, - participants: callState.callParticipants, - localVideoParticipantBuilder: ( - BuildContext context, - Call call, - CallParticipantState callState, - ) { - // Build local participant video - }, - ); - }, -); -``` - -## Change screensharing view - -If a user is screensharing, you can also customise the screensharing stream using the `screenShareContentBuilder` -parameter: - -```dart -StreamCallContent( - call: call, - callState: callState, - callParticipantsBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallParticipants( - call: call, - participants: callState.callParticipants, - screenShareContentBuilder: ( - BuildContext context, - Call call, - CallParticipantState callState, - ) { - // Build screensharing content view - }, - ); - }, -); -``` - -## Change grid layout - -There are two grid layouts that `stream_video_flutter` supports at the moment: grid and spotlight. - -You can change these via the `layoutMode` parameter: - -```dart -StreamCallContent( - call: call, - callState: callState, - callParticipantsBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallParticipants( - call: call, - participants: callState.callParticipants, - layoutMode: ParticipantLayoutMode.spotlight, - ); - }, -); -``` - -## Sort and filter participants - -Sorting changes the order of participants on the grid while filtering selects participants to display -according to the filters given. - -```dart -StreamCallContent( - call: call, - callState: callState, - callParticipantsBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallParticipants( - call: call, - participants: callState.callParticipants, - filter: (participant) { - // returning true displays the participant while returning false does not - return YOUR_CONDITION_HERE; - }, - sort: (a, b) { - // Returning an integer > 0 sorts a higher than b - // Add sorting code here - }, - ); - }, -); -``` - diff --git a/docusaurus/docs/Flutter/04-ui/_category_.json b/docusaurus/docs/Flutter/04-ui/_category_.json deleted file mode 100644 index 9b14d34ab..000000000 --- a/docusaurus/docs/Flutter/04-ui/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "UI Components" -} diff --git a/docusaurus/docs/Flutter/05-advanced/01-deeplinking.mdx b/docusaurus/docs/Flutter/05-advanced/01-deeplinking.mdx deleted file mode 100644 index 4e4c6c120..000000000 --- a/docusaurus/docs/Flutter/05-advanced/01-deeplinking.mdx +++ /dev/null @@ -1,266 +0,0 @@ ---- -id: call_deep_linking -sidebar_position: 1 -title: Call Deep Linking ---- - -# Implementing Call Deep Linking - -It's common in mobile calling apps that a call can be started from a link, that should start the app and dial in immediately. This can be accomplished by [universal links on iOS](https://developer.apple.com/ios/universal-links/) and [App links on Android](https://developer.android.com/training/app-links). - -In this guide we'll show you how you can handle such deep links to navigate to the call screen provided by our SDK. For the sake of simplicity, we'll use the [uni_links](https://pub.dev/packages/uni_links) plugin that allows handling iOS and Android deep links in a similar way. - -To get started, you first need to do some platform-specific configuration. - -## Enabling deep links on Android - -To handle deep links in Android you need to declare an intent filter in `android/app/src/main/AndroidManifest.xml` like it is shown in the example below: - -```xml - - - - - - - - -``` - -You can learn more about this structure in the [official documentation](https://developer.android.com/training/app-links/deep-linking), but the gist of it is this: - -* Adding the `` lets your `Activity` parse specific intents that come from inside or outside of your application. -* By adding the appropriate `` and `` tags, you let your `Activity` open and consume data that's browsable, such as URLs. -* The most important part is the `` tag. It allows you to parse the link in the format of `https://[YOUR_HOST]/join/`. Any URL that has that structure will be consumable by your `Activity`. - -But to make your published app associate with a hosted and published website and to stop potential security issues, the website needs to know how to recognize your app. - -You have to take your application `package-id` and its `SHA-256` fingerprint and use it to generate an `assetlinks.json file`. You can find the full process and documentation on the [official Android deep linking page](https://developer.android.com/training/app-links/verify-android-applinks#web-assoc). - -Once you've generated these fingerprints - **we recommend doing it for debug and release** **keystores** and your CI if it uses a different keystore than local setup - you can create the `assetlinks.json` file: - -```json -[{ // first application - "relation": ["delegate_permission/common.handle_all_urls"], - "target": { - "namespace": "android_app", - "package_name": "com.my.application.debug", - "sha256_cert_fingerprints": ["sha-256-fingerprint"] - } - }, - { // second application - "relation": ["delegate_permission/common.handle_all_urls"], - "target": { - "namespace": "android_app", - "package_name": "com.my.application", - "sha256_cert_fingerprints": ["sha-256-fingerprint"] - } -}] -``` - -Note that the `relation` and ` namespace` parts are not as important as the rest and how each object represents one application. - -Now that you have the file created, you need to upload it either to the root directory of your website, or to the `.well-known` directory. - -## Enabling deep links on iOS - -In order to support universal links, you need to have paid Apple developer account. On the Apple developer website, you will need to add the "associated domains" for your app id. - -Next, you need to enable the "Associated Domains" capability for your app in Xcode, and specify an app link, in the format `applinks:[YOUR_HOST]`. After that your `ios/Runner/Runner.entitlements` file should look like this: - -```xml - - - - - com.apple.developer.associated-domains - - applinks:[YOUR_HOST] - - - -``` - -Next, you need to upload `apple-app-site-association` file, either to the root directory of your website, or to the `.well-known` directory. The AASA (short for apple-app-site-association) is a JSON file that lives on your website and associates your domain with your native app. - -In its simplest form, your AASA file should have the following format: - -```json -{ - "applinks": { - "apps": [], - "details": [{ - "appID": "[YOUR_TEAM_ID].[YOUR_BUNDLE_ID]", - "paths": [ - "*" - ] - }] - } -} -``` - -You can also specify exact paths if you want to have stricter control over which ones can invoke your app. -You can also specify several apps on the same domain. - -Before proceeding, please make sure that the uploaded file is a valid one, and it's deployed at the right place. -For this, you can use Apple's [validation tool](https://search.developer.apple.com/appsearch-validation-tool). - -## Handling deep links - -To get started, you first need to add the [uni_links](https://pub.dev/packages/uni_links) plugin to your `pubspec.yaml`: - -```yaml -dependencies: - # Other dependencies - uni_links: -``` - -Next, use the snippet below to listen for incoming deep links and navigate to `JoinScreen` that we'll cover in the next step: - -```dart -import 'package:uni_links/uni_links.dart'; - -StreamSubscription? _deepLinkSubscription; - -Future _observeDeepLinks() async { - // The app was in the background. - if (!kIsWeb) { - _deepLinkSubscription = uriLinkStream.listen((uri) { - if (mounted && uri != null) _handleDeepLink(uri); - }); - } - - // The app was terminated. - try { - final initialUri = await getInitialUri(); - if (initialUri != null) _handleDeepLink(initialUri); - } catch (e) { - debugPrint(e.toString()); - } -} - -Future _handleDeepLink(Uri uri) async { - // Parse the call id from the deep link. - final callId = uri.queryParameters['id']; - if (callId == null) return; - - // return if the video user is not yet logged in. - // Replace the getCurrentUser() method with your method to retrieve the current user - final currentUser = getCurrentUser(); - if (currentUser == null) return; - - final streamVideo = StreamVideo.instance; - final call = streamVideo.makeCall(callType: kCallType, id: callId); - - try { - await call.getOrCreate(); - } catch (e, stk) { - debugPrint('Error joining or creating call: $e'); - debugPrint(stk.toString()); - return; - } - - // Your method to navigate to the lobby/call screen. - navigateToCallScreen(); -} -``` - -In this snippet, you: - -1. Handle the case when the app was in the background and is now brought to the foreground by a deep link. -2. Handle the case when the app was terminated and is now started by a deep link. -3. Extract the call ID from the deep link URL. -4. Navigate to a screen that will handle the call. - -While you can initialize the call on your call screen, you can also add an intermediary `JoinScreen` with the call initialization: - -```dart -class JoinScreen extends StatefulWidget { - const JoinScreen({ - super.key, - required this.callId, - }); - - final String callId; - - @override - State createState() => _JoinScreenState(); -} - -class _JoinScreenState extends State { - var _isInProgress = false; - - @override - void initState() { - super.initState(); - _joinCall(widget.callId); - } - - // Step 1 - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Joining call'), - ), - body: Center( - child: _isInProgress - ? const CircularProgressIndicator( - strokeWidth: 2, - ) - : const SizedBox(), - ), - ); - } - - // Step 2 - Future _joinCall(String callId) async { - setState(() => _isInProgress = true); - - try { - final call = StreamVideo.instance.makeCall( - id: callId, - callType: StreamCallType.defaultType(), - ); - - await call.join(); - - await _navigateToCall(call); - } catch (e) { - debugPrint(e.toString()); - } finally { - setState(() => _isInProgress = false); - } - } - - // Step 3 - Future _navigateToCall(Call call) async { - // Navigate to your call screen - } -} -``` - -Here's what you're doing here, step-by-step: - -1. Showing a connecting screen for the call while it initializes. -2. Joining the call with the call ID from the deep link. -3. Navigating to your call screen. - -## Testing deep links - -Finally, run your application, generate a call link using the schema above, and try opening the link. It should automatically redirect to your app and open the call. - -Alternatively, you can run the following commands from the command line: - -```shell -# Android -adb shell 'am start -W -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://[YOUR_HOST]/join/call123"' - -# iOS -/usr/bin/xcrun simctl openurl booted "https://[YOUR_HOST]/join/call123" -``` diff --git a/docusaurus/docs/Flutter/05-advanced/02-ringing.mdx b/docusaurus/docs/Flutter/05-advanced/02-ringing.mdx deleted file mode 100644 index 1e37b077f..000000000 --- a/docusaurus/docs/Flutter/05-advanced/02-ringing.mdx +++ /dev/null @@ -1,482 +0,0 @@ ---- -id: ringing_and_callkit -sidebar_position: 2 -title: Ringing and CallKit ---- - -Adding Ringing And CallKit To Your Application - -### Introduction - -This guide details how to add an end-to-end call flow (ringing) to your Flutter application. - -Ringing is done through a custom interface for Android and CallKit for iOS. An end-to-end call flow -allows you to add an immersive calling experience to your application. - -Ringing requires push/VoIP notifications to be sent to your device. Stream Video sends push/VoIP notifications to members that have at least one registered device. - -To receive push notifications from Stream Video, you'll need to: - -1. Configure your push notification provider on the Stream Dashboard. -2. Add the client-side integration. For Flutter this guide demonstrates using Firebase Cloud Messaging (FCM) for Android and Apple Push Notification Service (APNs) for iOS devices. - -:::warning - To get the best experience we strongly suggest using APNs for iOS. While our goal is to ensure compatibility with both providers on iOS, Firebase is not yet fully supported. -::: - -### Creating a ringing Call - -To create a ringing call, you need to follow the same steps as in the basic call flow with the difference of adding the `ringing` and `memberIds` parameters to the `getOrCreateCall()` method. - -```dart -final call = StreamVideo.instance.makeCall(callType: StreamCallType.defaultType(), id: 'Your-call-ID'); -await call.getOrCreate(memberIds: ['user1_id', 'user2_id'], ringing: true, video: true); -``` - -* When you set `ringing` to true, Stream will send a notification to the users on the call, triggering the platform call screen on iOS and Android. The ringing notification will indicate whether it's a video call or an audio-only call, depending on whether you set the `video` parameter to true or false. -* `memberIds` is a list of user IDs to immediately add to the call. Combining this with a `ringing` parameter will trigger the call to ring on the devices of the members. - -In subsequent steps, we will show you how to configure your Stream app in the Dashboard and your Flutter app to properly send and receive ringing notifications. - -### Common steps for both iOS and Android - -#### Configuring Push Notification Manager - -To handle push notifications, you need to configure the `pushNotificationManagerProvider` in the `StreamVideo` instance. -It manages device token registration, incoming call handling, and listening to call events (for example to end the call on the callee side when the caller ends the call). - -When creating a `StreamVideo` instance, you need to pass a `pushNotificationManagerProvider` parameter. This parameter is an instance of `StreamVideoPushNotificationManager` that is created using the `StreamVideoPushNotificationManager.create` method. - -```dart - StreamVideo( - // ... - options: const StreamVideoOptions( - // It's important to keep connections alive when the app is in the background to properly handle incoming calls while the app is in the background - keepConnectionsAliveWhenInBackground: true, - ), - // Make sure you initialise push notification manager - pushNotificationManagerProvider: StreamVideoPushNotificationManager.create( - iosPushProvider: const StreamVideoPushProvider.apn( - name: 'your-ios-provider-name', - ), - androidPushProvider: const StreamVideoPushProvider.firebase( - name: 'your-fcm-provider', - ), - pushParams: const StreamVideoPushParams( - appName: kAppName, - ios: IOSParams(iconName: 'IconMask'), - ), - ), - ); -``` - -- For `androidPushProvider` use the provider name we will create later in [Firebase integration](#Step-2---Upload-the-Firebase-Credentials-to-Stream) - -- For `iosPushProvider` use the provider name we will create later in [APN integration](#Integrating-APNs-for-iOS​) - -- Add app icon Asset in Xcode for displaying in CallKit screen dedicated button (named `IconMask` in the code below). [See details here](https://developer.apple.com/documentation/callkit/cxproviderconfiguration/2274376-icontemplateimagedata) - -#### Handling CallKit events (for both iOS and Android) - -CallKit events are events exposed by the `flutter_callkit_incoming` package that we utilize to handle incoming calls on both iOS and Android. -It is important to handle these events to ensure a seamless calling experience regardless of which provider is used for push. - -In a high-level widget in your app, add this code to listen to CallKit events: - -```dart -import 'package:rxdart/rxdart.dart'; - -final _compositeSubscription = CompositeSubscription(); - -@override -void initState() { - ... - _observeCallKitEvents() -} - -void _observeCallKitEvents() { - final streamVideo = StreamVideo.instance; - - // You can use our helper method to observe core CallKit events - // It will handled call accepted, declined and ended events - _compositeSubscription.add( - streamVideo.observeCoreCallKitEvents( - onCallAccepted: (callToJoin) { - // <---- IMPLEMENT NAVIGATION TO CALL SCREEN HERE - }, - ), - ); - - // Or you can handle them by yourself, and/or add additional events such as handling mute events from CallKit - // _compositeSubscription.add(streamVideo.onCallKitEvent(_onCallToggleMute)); -} - -@override -void dispose() { - // ... - _compositeSubscription.cancelAll(); -} -``` - -:::note -Remember to implement navigation in a marked line. -::: - -If you need to manage the CallKit call, you can use the `StreamVideo.pushNotificationManager`. As an example, let's -say you want to end all calls on the CallKit side, you can end them this way: - -```dart -StreamVideo.instance.pushNotificationManager?.endAllCalls(); -``` - -#### Handling calls while in the foreground - -You can manage an incoming call by listening to Stream events and displaying the incoming call screen within your app. - -```dart -StreamVideo.instance.state.incomingCall.listen(_onNavigateToCall); -``` - -If you navigate to your call screen, that uses `StreamCallContainer`, while the call is still ringing (not yet accepted) the incoming call screen will be displayed. - -:::info -This method will not show an incoming call screen when the app is in the background or terminated state. To handle this, you would need proper VoIP push handling. Additionally, if VoIP push/CallKit is configured, it will display a ringing notification while also showing the incoming screen when the app is in the foreground. -::: - -### Integrating Firebase for Android - -#### Step 1 - Get the Firebase Credentials - -These credentials are the [private key file](https://firebase.google.com/docs/admin/setup#initialize_the_sdk_in_non-google_environments) for your service account, in Firebase console. - -To generate a private key file for your service account in the Firebase console: - -- Open Settings > Service Accounts. - -- Click **Generate New Private Key**, then confirm by clicking **Generate Key**. - -- Securely store the JSON file containing the key. - -This JSON file contains the credentials that need to be uploaded to Stream’s server, as explained in the next step. - -#### Step 2 - Upload the Firebase Credentials to Stream - -You now need to upload your Firebase credentials using the Stream dashboard. - -- Go to the dashboard of your video project at the [Stream website](https://dashboard.getstream.io). - -- Open the **Push Notifications** tab under **Video & Audio**. - -- Select **New Configuration** and select **Firebase**. - -![Firebase Configuration](../assets/advanced_assets/firebase_config.png) - -- Add a name for your push provider in the **Name** field. You will use this name later in the code to identify which provider to use for Android notifications. - -- Add your previously generated Firebase Credentials in the **Credentials JSON** field. - -- Enable this provider using toggle button. - -- Click **Create** and your push provider should be ready. - -#### Step 3 - Add dependencies to your app - -To integrate push notifications in your Flutter app, you need to use the [`firebase_messaging`](https://pub.dev/packages/firebase_messaging) package. - -Follow the [Flutter Firebase documentation](https://firebase.flutter.dev/docs/messaging/overview/#installation) to set up the plugin for Android and iOS. -Make sure you complete additional setup described [here](https://firebase.flutter.dev/docs/messaging/apple-integration/) and [here](https://firebase.google.com/docs/cloud-messaging/flutter/client). - -Once that's done, FCM should be able to send push notifications to your devices. - -#### Step 4 - Add native permissions - -Add these permissions to `AndroidManifest.xml` in order to support video calling: - -```xml - - - - - - - - - - - - -``` - -#### Step 5 - Add code to listen to push notifications - -We recommend storing user credentials locally when the user logs in so you can automatically set up the user when -a push notification is received. - -- Add the following code in your `main.dart` as global functions to listen to background notifications: - -- Replace `yourUserCredentialsGetMethod()` with your implementation to get logged in user credentials - -- Configure `pushNotificationManagerProvider` in the same way you did in the previous setup steps - -```dart -// As this runs in a separate isolate, we need to setup the app again. -@pragma('vm:entry-point') -Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { - - // Initialise Firebase - await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); - - try { - // Get stored user credentials - var credentials = yourUserCredentialsGetMethod(); - if (credentials == null) return; - - // Initialise StreamVideo - StreamVideo( - // ... - // Make sure you initialise push notification manager - pushNotificationManagerProvider: StreamVideoPushNotificationManager.create( - iosPushProvider: const StreamVideoPushProvider.apn( - name: 'your-ios-provider-name', - ), - androidPushProvider: const StreamVideoPushProvider.firebase( - name: 'your-fcm-provider', - ), - pushParams: const StreamVideoPushParams( - appName: kAppName, - ios: IOSParams(iconName: 'IconMask'), - ), - ), - ); - - // Observe Declined CallKit event to handle declining the call even when app is terminated - streamVideo.observeCallDeclinedCallKitEvent(); - - // Pass it along to the handler - await _handleRemoteMessage(message); - } catch (e, stk) { - debugPrint('Error handling remote message: $e'); - debugPrint(stk.toString()); - } - - StreamVideo.reset(); -} - -Future _handleRemoteMessage(RemoteMessage message) async { - await StreamVideo.instance.handleVoipPushNotification(message.data); -} -``` - -In a high-level widget in your app, add this code to listen to FCM messages: - -```dart -@override -void initState() { - ... - _observeFcmMessages() -} - -_observeFcmMessages() { - FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); - _fcmSubscription = FirebaseMessaging.onMessage.listen(_handleRemoteMessage); -} -``` - -The code until this point handles calls for the background and foreground state of the app. -To handle calls from a terminated state, we need to add some additional code. - -In a high-level widget, add this method and call it from the `initState()` method: - -:::info -Add navigator key to MaterialApp widget: `navigatorKey: _navigatorKey`. -::: - -```dart -final _navigatorKey = GlobalKey(); - -@override -void initState() { - //... - _tryConsumingIncomingCallFromTerminatedState(); -} - -void _tryConsumingIncomingCallFromTerminatedState() { - // This is only relevant for Android. - if (CurrentPlatform.isIos) return; - - if (_navigatorKey.currentContext == null) { - // App is not running yet. Postpone consuming after app is in the foreground - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - _consumeIncomingCall(); - }); - } else { - // no-op. If the app is already running we'll handle it via events - } -} - -Future _consumeIncomingCall() async { - final calls = await StreamVideo.instance.pushNotificationManager?.activeCalls(); - if (calls == null || calls.isEmpty) return; - - final callResult = await StreamVideo.instance.consumeIncomingCall( - uuid: calls.first.uuid!, - cid: calls.first.callCid!, - ); - - callResult.fold(success: (result) async { - final call = result.data; - await call.accept(); - - //Navigate to call screen <---- IMPLEMENT NAVIGATION HERE - }, failure: (error) { - debugPrint('Error consuming incoming call: $error'); - }); -} -``` - -#### Step 6 - Request notification permission from user - -For Android 13+ you need to request the `POST_NOTIFICATIONS` permission. You can do it using the [permission_handler](https://pub.dev/packages/permission_handler) package. - -Remember to follow [official best practices](https://developer.android.com/develop/ui/views/notifications/notification-permission#best-practices) (especially showing prompt before the request). - - -### Integrating APNs for iOS - -#### Step 1 - Get the iOS certificate for push notifications - -- Generate push notification service key [here](https://developer.apple.com/account/resources/certificates/add). Make sure you select **Apple Push Notifications service SSL (Sandbox & Production)**. - -- You will need to create **Certificate Signing Request** - [follow this steps](https://developer.apple.com/help/account/create-certificates/create-a-certificate-signing-request) - -- Convert the *aps.cer* file you created in the last step to a .p12 certificate file using keychain access. Make sure that you configure no password for the p12 file. - - - Add app.cer to login keychain - - - Find it in Certificate tab, right click and export as .p12 file - - - Remember not to set any password while exporting - -#### Step 2 - Upload the certificate and create a push provider - -- Go to the dashboard of your video project at the [Stream website](https://dashboard.getstream.io). - -- Open the **Push Notifications** tab under **Video & Audio**. - -- Select **New Configuration** and select **APN**. - -![APNs Configuration](../assets/advanced_assets/apns_config.png) - -- Add a name for your push provider in the **Name** field. This is the name used while setting up iOS push notifications in the code we did [earlier](#Step-5---Add-code-to-listen-to-push-notifications) - -- Add your previously generated P12 file with your additional Apple information. - -- Enable this provider using toggle button - -- Click **Create** and your push provider should be ready. - -#### Step 3 - Add dependencies - -There are no dependencies on the Flutter side that you need to add specifically for iOS. - -#### Step 4 - Add native permissions - -Add these permissions to `Info.plist` in order to support video calling: - -```plist -NSCameraUsageDescription -$(PRODUCT_NAME) needs access to your camera for video calls. -NSMicrophoneUsageDescription -$(PRODUCT_NAME) needs access to your microphone for voice and video calls. -UIApplicationSupportsIndirectInputEvents - -BGTaskSchedulerPermittedIdentifiers - - $(PRODUCT_BUNDLE_IDENTIFIER) - -UIBackgroundModes - - audio - fetch - processing - remote-notification - voip - -``` - -#### Step 5 - Add callback to handle call in terminated state - -When an iOS app is terminated, the Flutter engine is not running. The engine needs to be started up to handle Stream call events whenever a call is received by the app. The Stream SDK performs the job of running a Flutter engine instance whenever a call is received. However, on the app side, a callback handle needs to be registered that will connect to `StreamVideo`. - -```dart -@pragma('vm:entry-point') -Future _backgroundVoipCallHandler() async { - WidgetsFlutterBinding.ensureInitialized(); - - // Get stored user credentials - var credentials = yourUserCredentialsGetMethod(); - if (credentials == null) return; - - // Initialise StreamVideo - StreamVideo( - // ... - // Make sure you initialise push notification manager - pushNotificationManagerProvider: StreamVideoPushNotificationManager.create( - iosPushProvider: const StreamVideoPushProvider.apn( - name: 'your-ios-provider-name', - ), - androidPushProvider: const StreamVideoPushProvider.firebase( - name: 'your-fcm-provider', - ), - pushParams: const StreamVideoPushParams( - appName: kAppName, - ios: IOSParams(iconName: 'IconMask'), - ), - ), - ); -} -``` - -The `_backgroundVoipCallHandler` method should then be set when StreamVideo is initialised: - -```dart -StreamVideo( - // ... - pushNotificationManagerProvider: StreamVideoPushNotificationManager.create( - // ... - backgroundVoipCallHandler: _backgroundVoipCallHandler, - ), - ); -``` - -#### Step 6 - Add native code to the iOS project - -In your iOS project, add the following imports to your `AppDelegate.swift`: - -```swift -import UIKit -import Flutter -import stream_video_push_notification -``` - -In the same file, add an extra line to your `AppDelegate` class which registers the app for push notifications: - -```swift -override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? -) -> Bool { - GeneratedPluginRegistrant.register(with: self) - - // Register for push notifications. - StreamVideoPKDelegateManager.shared.registerForPushNotifications() - - return super.application(application, didFinishLaunchingWithOptions: launchOptions) -} -``` - -### Registering a Device With Stream Backend - -Once you configure a push provider and set it up on the Stream dashboard, a device that is supposed to receive push notifications needs to be registered on the Stream backend. - -Device registration is carried out in the SDK every time a user logs in and does not need to be implemented in your app. diff --git a/docusaurus/docs/Flutter/05-advanced/03-screen-sharing.mdx b/docusaurus/docs/Flutter/05-advanced/03-screen-sharing.mdx deleted file mode 100644 index 081f16983..000000000 --- a/docusaurus/docs/Flutter/05-advanced/03-screen-sharing.mdx +++ /dev/null @@ -1,208 +0,0 @@ ---- -id: screen_sharing -sidebar_position: 4 -title: Screen Sharing ---- - -### Introduction -During the duration of a call, participants may want to share either a portion of their screen, application or their entire screen to other users on the call. Stream Video makes it easy to support screensharing to other users natively on both Android and iOS devices. - -In this guide, we will look at the steps required to configure screensharing on both platforms. If you are interested in screensharing for just one platform, you can skip to the [Android](#android) or [iOS](#ios) section using this link. - -### iOS -Starting with iOS, there are two main options for screensharing from an iOS device. These are: - -- **in-app screensharing** - In this mode, the app's screen is only shared while the app is active or in the foreground. If the app is not in the foreground, screensharing is paused. -- **broadcasting** - Using broadcasting mode allows the app to share the contents of the screen even when the application goes into the background. - -Both of these options use Apple's framework [ReplayKit](https://developer.apple.com/documentation/replaykit) (via [flutter_webrtc](https://pub.dev/packages/flutter_webrtc)) for broadcasting the user's screen. - -![Screen sharing dashboard](../assets/advanced_assets/screen_sharing_dashboard.png) - -:::info - Before a user can share their screen, the call must have the screensharing capability configured via the [Dashboard](https://dashboard.getstream.io/). -::: - -#### In-app sharing -In-app screensharing only shares the application's screens. While in a call, screensharing can be enabled by calling `call.setScreenShareEnabled(enabled: true)` method. - -```dart - void startSharing() { - // Checks to ensure the user can share their screen. - final canShare = call.hasPermission(CallPermission.screenshare); - - if (canShare) { - // Set screensharing to enabled - call.setScreenShareEnabled(enabled: true); - } - } -``` - - -:::tip -If you use our UI components you can also add `ToggleScreenShareOption` as one of `StreamCallControls` option. -::: - -When the method is invoked, ReplayKit will ask for the user's consent that their screen will be shared. Only after the permission is granted, the screensharing starts. - -#### Broadcasting -In most cases, you would need to share your screen while the app is in the background, to be able to open other apps. For this, you need to create a Broadcast Upload Extension. - -##### Toggle screen sharing with broadcast mode - -If you want to start screen sharing in broadcast mode on iOS you will need to toggle it by setting `useiOSBroadcastExtension` flag to true in `ScreenShareConstraints`. You can set the constraints inside `ToggleScreenShareOption` or when you use `call.setScreenShareEnabled()` directly. - -```dart -const constraints = ScreenShareConstraints( - useiOSBroadcastExtension: true, -); - -... - -ToggleScreenShareOption( - ... - screenShareConstraints: constraints, -), - -//or - -call.setScreenShareEnabled(enabled: true, constraints: constraints); - -``` - -##### Add Broadcast Upload Extension - -iOS requires the use of Broadcast Upload Extensions to facilitate screen sharing when your app is in the background. This extension provides the necessary framework to handle capturing and broadcasting the screen content. - -Now add the extension, without UI, to your project in Xcode: - -![Screen sharing dashboard](../assets/advanced_assets/broadcast-extension.png) -![Screen sharing dashboard](../assets/advanced_assets/broadcast-extension-config.png) - -:::warning -Make sure the deployment target for both your app and broadcast extension is set to iOS 14 or newer. -::: - -After you create the extension, there should be a class called `SampleHandler`, that implements the `RPBroadcastSampleHandler` protocol. Remove the protocol conformance and the methods, import our `stream_video_screen_sharing`, and make the `SampleHandler` a subclass of our class called `BroadcastSampleHandler`, that internally handles the broadcasting. - -![Screen sharing dashboard](../assets/advanced_assets/broadcast-handler-implementation.png) - -To have access to our Handler implementation add `stream_video_screen_sharing` package to your app's `pubspec.yaml` file: - -```yaml -dependencies: - stream_video_screen_sharing: ^ -``` - -Then for native code to see it, add it as a dependency manually for the extension target in the Podfile file: - -```Podfile -target 'YOUR_EXTENSION_NAME' do - use_frameworks! - pod 'stream_video_screen_sharing', :path => File.join('.symlinks', 'plugins', 'stream_video_screen_sharing', 'ios') -end -``` - -:::note -Replace `YOUR_EXTENSION_NAME` with the name of the extension you created. -::: - -##### Setup app groups - -Add your extension to an app group by going to your extension's target in the project. In the Signings & Capabilities tab, click the + button in the top left and add App Groups. If you haven't done so already, add App Groups to your main app as well, ensuring that the App Group identifier is the same for both. - -##### Update Info.plist - -Finally, you should add a new entries in the `Info.plist` files. -In **both the app and the broadcast extension**, add a key `RTCAppGroupIdentifier` with a value of the app group id and `RTCScreenSharingExtension` key with a value of a bundle id of your extension. - -With that, the setup for the broadcast upload extension is done. - -### Android - -The Stream Video SDK has support for screen sharing from an Android device. The SDK is using the [Android Media Projection API](https://developer.android.com/guide/topics/large-screens/media-projection) for the capture. To initiate screen sharing, user consent is mandatory. - -When using the `ToggleScreenShareOption` within the` stream_video_flutter` package, permission handling is seamlessly integrated. However, if you opt to initiate screen sharing via the `setScreenShareEnabled()` method on the `Call` object, you will be responsible for securing the necessary permissions and initiating a foreground service. The foreground service is essential for displaying a notification to the user while screen sharing is active. -It is required to start [media projection foreground service](https://developer.android.com/reference/android/media/projection/MediaProjectionManager#getMediaProjection(int,%20android.content.Intent)) from Android version 10 onward. - -From Android 14 onward, it is also required to actively ask users for a permission to share their screen. You can do this by calling `call.requestScreenSharePermission()` method. -Below is an example snippet that demonstrates how to use our built in `StreamBackgroundService` class to manage these requirements: - -```dart - void startScreemSharing() { - if (CurrentPlatform.isAndroid) { - // Check if the user has granted permission to share their screen - if (!await call.requestScreenSharePermission()) { - return; - } - - // Start the screen sharing notification service - await StreamBackgroundService() - .startScreenSharingNotificationService(call); - } - - // Enable screen sharing - final result = await call.setScreenShareEnabled( - enabled: true, - ); - - // Stop the screen sharing notification service if the operation failed - if (CurrentPlatform.isAndroid && result.isFailure) { - await StreamBackgroundService() - .stopScreenSharingNotificationService(); - } - } -``` - -Remember to stop the foreground service when the screen sharing is disabled: - -```dart - void stopScreenSharing() async { - final result = await call.setScreenShareEnabled( - enabled: false, - ); - - if (CurrentPlatform.isAndroid) { - await StreamBackgroundService() - .stopScreenSharingNotificationService(); - } - } -``` - -You can customize the notification content and behavior by initiating `StreamBackgroundService`: - -```dart -StreamBackgroundService.init( - StreamVideo.instance, - onNotificationClick: (call) async { - //TODO navigate to call - }, - onButtonClick: (call, type, serviceType) async { - switch (serviceType) { - case ServiceType.call: - call.end(); - case ServiceType.screenSharing: - StreamVideoFlutterBackground.stopService(ServiceType.screenSharing); - call.setScreenShareEnabled(enabled: false); - } - }, -); -``` - -### Screen sharing settings - -You can customize the screen sharing behavior by providing `ScreenShareConstraints` to the `ToggleScreenShareOption` widget or `setScreenShareEnabled()` method. - -You can specify the following settings: - -- `useiOSBroadcastExtension` - Set to `true` to enable broadcast mode on iOS. - -- `captureScreenAudio` - Set to `true` to capture audio from the screen. - -- `sourceId` - The device ID of an audio source, if you want to capture audio from a specific source. - -- `maxFrameRate` - The maximum frame rate for the screen sharing video. - -- `params` - The video parameters for the screen sharing video. - -For `params` you can use one of our predefined presets in `RtcVideoParametersPresets`. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/05-advanced/04-picture-in-picture.mdx b/docusaurus/docs/Flutter/05-advanced/04-picture-in-picture.mdx deleted file mode 100644 index 1c128d3d7..000000000 --- a/docusaurus/docs/Flutter/05-advanced/04-picture-in-picture.mdx +++ /dev/null @@ -1,129 +0,0 @@ ---- -id: picture_in_picture -sidebar_position: 5 -title: Picture in Picture (PiP) ---- - -Picture in picture (PIP) keeps the call running and visible while you navigate to other apps. - -### Enable Picture-in-Picture -You can enable Picture in Picture by setting the `enablePictureInPicture` property to `true` in the `PictureInPictureConfiguration` provided to `StreamCallContainer` or `StreamCallContent` widget. - -```dart -StreamCallContainer( - call: widget.call, - pictureInPictureConfiguration: const PictureInPictureConfiguration( - enablePictureInPicture: true, - ), -) -``` - -## Android - -### Android Configuration -To enable Picture in Picture on Android, you need to add the following configuration to your `AndroidManifest.xml` file. - -```xml - -``` - -Then you need to add this code to your `MainActivity` class. It will enter Picture in Picture mode when the user leaves the app but only if the call is active. - -```kotlin -import io.flutter.embedding.android.FlutterActivity -import io.getstream.video.flutter.stream_video_flutter.service.PictureInPictureHelper - -class MainActivity: FlutterActivity() { - override fun onUserLeaveHint() { - super.onUserLeaveHint() - PictureInPictureHelper.enterPictureInPictureIfInCall(this) - } -} -``` - -### Android Customization - -For Android, you can customize the widget rendered while app is in Picture-in-Picture mode by providing `callPictureInPictureBuilder` to `PictureInPictureConfiguration`. - -```dart - StreamCallContainer( - call: widget.call, - callContentBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallContent( - call: call, - callState: callState, - pictureInPictureConfiguration: const PictureInPictureConfiguration( - enablePictureInPicture: true, - androidPiPConfiguration: AndroidPictureInPictureConfiguration( - callPictureInPictureBuilder: (context, call, callState) { - // YOUR CUSTOM WIDGET - }, - ) - ), - ); - }, - ); -``` - -## iOS - -### Local camera feed in Picture-in-Picture mode - -By default iOS is not allowing usage of local camera feed when app is in the background. That includes Picture in picture mode and Split View mode. To enable it you need to request the [multitasking-camera-access](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_avfoundation_multitasking-camera-access) permission directly from Apple (this will change from iOS 18). -If you already have the permission you have to enable local feed support in our PiP implementation by setting `ignoreLocalParticipantVideo` to `false`. - -```dart - StreamCallContainer( - call: widget.call, - callContentBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallContent( - call: call, - callState: callState, - pictureInPictureConfiguration: const PictureInPictureConfiguration( - enablePictureInPicture: true, - iOSPiPConfiguration: IOSPictureInPictureConfiguration( - ignoreLocalParticipantVideo: false, - ) - ), - ); - }, - ); -``` - -### Enabling PiP support with custom call content widget - -If you are not using our `StreamCallContent` and instead building custom call content widget you can still enable Picture in Picture mode by adding `StreamPictureInPictureUiKitView` anywhere in the widget tree. This widget will handle the Picture in Picture mode in iOS for you. - -```dart - StreamCallContainer( - call: widget.call, - callContentBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return Stack( - children: [ - StreamPictureInPictureUiKitView(call: call), - // YOUR CUSTOM WIDGET - ], - ); - }, - ); -``` - -Done. Now after leaving the app, you'll see that the call will be still alive in the background like the one below: - -![Picture in Picture example](../assets/advanced_assets/pip_example.png) \ No newline at end of file diff --git a/docusaurus/docs/Flutter/05-advanced/05-call-recording.mdx b/docusaurus/docs/Flutter/05-advanced/05-call-recording.mdx deleted file mode 100644 index 690c857b6..000000000 --- a/docusaurus/docs/Flutter/05-advanced/05-call-recording.mdx +++ /dev/null @@ -1,54 +0,0 @@ ---- -slug: /recording -sidebar_position: 6 -title: Recording ---- -A key feature of modern communication tools is the ability to quickly and easily record calls. This functionality is used for everything from quality assurance and training to legal compliance or simply as a matter of convenience for keeping track of conversations and later reviewing them. - -In this guide, we will look at how developers using Stream Video can easily record their calls using our Flutter SDK. We will cover the technical details involved in starting, stopping, and observing the state of the call recording. - -### Recording -The `Call` object provides access to the recording API, enabling you to start and stop call recordings. To initiate recording, you can use the `call.startRecording` method on the active call object. Additionally, you can check the current recording status by accessing the `callState.isRecording` property. Monitoring this property allows you to update your application's UI to indicate whether the current call is being recorded. - -```dart -StreamCallContent( - call: call, - callState: callState, - callControlsBuilder: (context, call, callState) { - final recording = callState.isRecording; // `isRecording` tells us whether the call is currently being recorded - return StreamCallControls(options: [ - // We can add a custom call option which can be used to start and stop recording - CallControlOption( - icon: recording - ? const Icon(Icons.emergency_recording, - color: Colors.red) - : const Icon(Icons.emergency_recording, - color: Colors.grey), - onPressed: () { - if (!recording) { - // If we are not recording, we can start recording the current call - call.startRecording(); - } else { - // If we are recording, we can stop recording the current call - call.stopRecording(); - } - }, - ), - ]); - }, -); -``` - -### Permissions - -Before the user is allowed to start recording, the user must have the corresponding permissions. As a form of best practice, we encourage integrators to check the permissions before allowing users to execute a given action. Permissions for each app and user role can be found on the Stream dashboard. Please visit https://dashboard.getstream.io/ to view and change the permission scope for your app. - -### Retrieving the call recordings - -The call recording data can be retrieved by calling the `listRecordings()` method of `Call` class. By default, this method will use the current call id (`CID`) to look up the recordings for the current call session. The method returns `List` which allows you to loop over the different recording objects. - -You can also call the `listRecordings()` method on the `StreamVideo` instance and specify the `cid` of the call you want to retrieve recordings for. - -:::tip -Multiple recordings can be made during a single call session, and a single call CID can also be reused for multiple sessions. -::: \ No newline at end of file diff --git a/docusaurus/docs/Flutter/05-advanced/06-screenshots.mdx b/docusaurus/docs/Flutter/05-advanced/06-screenshots.mdx deleted file mode 100644 index a502484ab..000000000 --- a/docusaurus/docs/Flutter/05-advanced/06-screenshots.mdx +++ /dev/null @@ -1,18 +0,0 @@ ---- -slug: /screenshots -sidebar_position: 7 -title: Screenshots ---- -You can take a picture of a VideoTrack at highest possible resolution. This can be useful for example if you want to take a screenshot of a screenshare at full resolution. - -```dart -final participant = call.state.value.otherParticipants.first; -final screenshot = call.takeScreenshot(participant); -``` - -In case you want to take a screenshot of a screen-sharing track, you can specify which track type you want to capture: - -```dart -final participant = call.state.value.otherParticipants.first; -final screenshot = call.takeScreenshot(participant, trackType: SfuTrackType.screenShare); -``` diff --git a/docusaurus/docs/Flutter/05-advanced/07-background-modes.mdx b/docusaurus/docs/Flutter/05-advanced/07-background-modes.mdx deleted file mode 100644 index c0c4aec17..000000000 --- a/docusaurus/docs/Flutter/05-advanced/07-background-modes.mdx +++ /dev/null @@ -1,129 +0,0 @@ ---- -title: Background modes -slug: /background-modes -sidebar_position: 8 -description: How to keep the call alive in the background ---- - -Ensuring that calls continue seamlessly when the app is in the background is essential for delivering a reliable and smooth user experience. On this page, you will learn how to make sure that calls remain active in the background on both Android and iOS. - -## Android - -The Stream Video Flutter SDK includes a dedicated service to keep calls active in the background, allowing users to multitask seamlessly. - -### Starting the Android foreground service - -The Stream Video Flutter SDK ensures continuous calls by initiating an Android foreground service. This service keeps the process active and the call running, even if the application's UI is no longer visible. The SDK already provides the required declarations in the manifest, all you have to do is to initialize the service somewhere after starting the app. - -```dart -StreamBackgroundService.init( - StreamVideo.instance, -); -``` - -Our foreground service displays a notification indicating an ongoing call. This notification allows users to either exit the call or seamlessly return to it. It appears during active calls and vanishes when the user leaves the call. - -![Active call notification](../assets/advanced_assets/active_call_notification.png) - -### Screen sharing notification - -When a user shares their screen, the SDK displays a notification to indicate that the screen is being shared. This notification allows users to either stop sharing their screen or return to the call. It appears during active screen sharing and vanishes when the user stops sharing their screen. - -![Screen sharing notification](../assets/advanced_assets/screen_sharing_notification.png) - -### Customizing the notification - -You can customize the notification by providing your own notification options. The SDK provides default options for both the call and screen sharing notifications. You can override these options by passing your own `NotificationOptionsBuilder` to the `init` method. - -```dart -StreamBackgroundService.init( - StreamVideo.instance, - callNotificationOptionsBuilder: (call) { - return const NotificationOptions( - content: NotificationContent( - title: 'Call Active', - text: 'You are in a call', - ), - avatar: NotificationAvatar( - url: '{url_to_avatar}', - ), - ); - }, -); -``` - -### Handling notification clicks - -You can handle notification clicks by providing callbacks to the `init` method. The callback is triggered when the user taps on the notification or on a notification button. You can use this callback to bring the call back to the foreground, cancel the call or perform any other action. - -By default, the SDK handles button tap by canceling the call when the user taps on the call notification and canceling screen-sharing when tapped on the screen-sharing notification. You can override this behavior by providing your own `onButtonClick` callback. - -```dart - StreamBackgroundService.init( - StreamVideo.instance, - onButtonClick: (call, type, serviceType) async { - switch (serviceType) { - case ServiceType.call: - // Add or replace with custom behavior - await call.leave(); - await call.reject(reason: CallRejectReason.cancel()); - case ServiceType.screenSharing: - // Add or replace with custom behavior - StreamVideoFlutterBackground.stopService(ServiceType.screenSharing); - call.setScreenShareEnabled(enabled: false); - } - }, - ); -``` - -### Required permissions - -We require the following permissions to create an appropriate foreground service: `FOREGROUND_SERVICE`, `FOREGROUND_SERVICE_PHONE_CALL`, and `FOREGROUND_SERVICE_MICROPHONE`. Additionally, the `FOREGROUND_SERVICE_MEDIA_PROJECTION` permission is necessary for the screen sharing functionality. They are added out-of-the-box as part of our `stream_video_flutter` package. - -:::note -Because of the foreground service type it requires a microphone (`RECORD_AUDIO`) permission to be enabled. Make sure the user grants the permission before beginning the call, otherwise the service will not be able to start. -::: - -## iOS - -iOS background modes provide the necessary framework to maintain connectivity, handle incoming calls, and manage ongoing calls even when the app isn't in the foreground. By using the appropriate background modes, your app can stay responsive to call events without being suspended by the system. - -### Enabling background modes - -* In Xcode, go to your app's target, select the Signing & Capabilities tab. - -* Click the + Capability button and add Background Modes. - -* Check the relevant background modes, specifically: - * Audio, AirPlay, and Picture in Picture: For ongoing audio/video calls while the app is in the background. - * Voice over IP (VoIP): This mode is critical for managing incoming and ongoing voice calls. - * Remote notifications - * Background processing - -![Active call notification](../assets/advanced_assets/background_modes.png) - -### Info.plist - -Make sure to add relevant permissions to your `Info.plist` file as well as the `BGTaskSchedulerPermittedIdentifiers` to support background tasks. - -```plist -NSCameraUsageDescription -$(PRODUCT_NAME) needs access to your camera for video calls. -NSMicrophoneUsageDescription -$(PRODUCT_NAME) needs access to your microphone for voice and video calls. -BGTaskSchedulerPermittedIdentifiers - - $(PRODUCT_BUNDLE_IDENTIFIER) - -UIBackgroundModes - - audio - processing - remote-notification - voip - -``` - -## Picture in Picture (PiP) - -To enhance the user experience even more, consider enabling Picture in Picture (PiP) mode. PiP allows users to continue watching videos or participating in calls while using other apps. The Stream Video Flutter SDK supports PiP mode on both iOS and Android, making it easy to enable this feature in your app. Check out our [Picture in Picture](https://getstream.io/video/docs/flutter/advanced/picture_in_picture/) guide to learn more. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/05-advanced/08-custom-data.mdx b/docusaurus/docs/Flutter/05-advanced/08-custom-data.mdx deleted file mode 100644 index ba4453ee5..000000000 --- a/docusaurus/docs/Flutter/05-advanced/08-custom-data.mdx +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: Custom Data -slug: /custom-data -sidebar_position: 9 -description: Learn how to add and read custom data in the Stream Video Flutter SDK. ---- - -Custom data is additional information that can be added to the default data of Stream. It is a dictionary of key-value pairs that can be attached to users, events, and pretty much almost every domain model in the Stream SDK. - -In the SDK, custom data is represented by the `Map`. This means that the key must be a string and the value can be any object. - -## Adding Custom Data - -Adding extra data can be done through the Server-Side SDKs or through the Client SDKs. In the Flutter Stream Video SDK, you can add extra data when creating/updating a call, updating a user and sending event or reaction. - -###### Example of updating the call custom data - -```dart -call.update(custom: {'mycustomfield': 'mycustomvalue'}); -``` - -###### Example of sending a reaction with custom data - -```dart -call.sendReaction( - reactionType: 'raise-hand', - emojiCode: ':smile:', - custom: {'mycustomfield': 'mycustomvalue'}, -); -``` - -###### Example of sending a custom event with custom data - -```dart -call.sendCustomEvent( - eventType: 'my-custom-event', - custom: {'mycustomfield': 'mycustomvalue'}, -); -``` - -###### Example of updating the user custom data while initializing the StreamVideo - -```dart -StreamVideo( - apiKey, - user: User.regular(userId: 'userId', extraData: {'mycustomfield': 'mycustomvalue'}), - userToken: token, -); -``` - -## Reading Custom Data -​ -Reading the custom data is as simple as accessing the `custom` field of the object. For example, to read the custom data of a reaction, you can access the `custom` field of the reaction event object. - -```dart -call.callEvents.listen((event) { - if (event is StreamCallReactionEvent) { - final customData = event.custom; - } -}); -``` - -For `Call` object the custom data is stored in call metadata that can be accessed when calling `getOrCreate()` or `get()` method. - -```dart -final result = await call.getOrCreate(); -final customData = result.fold( - success: (success) => success.data.data.metadata.details.custom, - failure: (_) => null, -); - -//or - -final result = await call.get(); -final customData = result.fold( - success: (success) => success.data.metadata.details.custom, - failure: (_) => null, -); -``` \ No newline at end of file diff --git a/docusaurus/docs/Flutter/05-advanced/09-push-notifications.mdx b/docusaurus/docs/Flutter/05-advanced/09-push-notifications.mdx deleted file mode 100644 index 2d26a94ed..000000000 --- a/docusaurus/docs/Flutter/05-advanced/09-push-notifications.mdx +++ /dev/null @@ -1,163 +0,0 @@ ---- -title: Push Notifications -slug: /push-notifications -sidebar_position: 3 -description: Learn how to enable push notifications in the Stream Video Flutter SDK. ---- - -Apart from the VoIP notifications for call ringing features, Stream Video Flutter SDK also supports standard push notifications. This guide will show you how to enable push notifications in your Flutter app using the Stream Video SDK. - -Push notifications are sent in the following scenarios: -- you create a call with the `ring` value set to true. In this case, a notification that shows a ringing screen is sent. (covered in the [ringing documentation](https://getstream.io/video/docs/flutter/advanced/ringing_and_callkit/)) -- you create a call with the `notify` value set to true. In this case, a regular push notification is sent. -- you haven't answered a call. In this case, a missed call notification is sent (regular push notification). - -## Android and Firebase Cloud Messaging (FCM) - -For FCM the steps taken in [ringing documentation](https://getstream.io/video/docs/flutter/advanced/ringing_and_callkit/) are enough and will also handle standard push notifications. - -In case of missed call the notification will be shown using [flutter_callkit_incoming](https://pub.dev/packages/flutter_callkit_incoming) package. It can be configured by `pushParams` when initializing `StreamVideo`: - -```dart -StreamVideo( - apiKey, - user: user, - pushNotificationManagerProvider: StreamVideoPushNotificationManager.create( - iosPushProvider: const StreamVideoPushProvider.apn( - name: 'apn', - ), - androidPushProvider: const StreamVideoPushProvider.firebase( - name: 'firebase', - ), - pushParams: const StreamVideoPushParams( - appName: kAppName, - ios: IOSParams(iconName: 'IconMask'), - missedCallNotification: NotificationParams( - showNotification: true, - subtitle: 'Missed Call', - callbackText: 'Call Back', - ) - ), - ), -); -``` - -If you want to handle missed call notification differently or handle the notification about incoming call (when `notify` is set to true) use the existing `_handleRemoteMessage()` method (see [ringing documentation](https://getstream.io/video/docs/flutter/advanced/ringing_and_callkit/)): - -```dart -Future _handleRemoteMessage(RemoteMessage message) async { - final payload = message.data; - - final sender = payload['sender'] as String?; - final type = payload['type'] as String?; - - if (sender == 'stream.video' && type == 'call.notification') { - final callCid = payload['call_cid'] as String?; - // Show notification, for example using `flutter_local_notifications` package - } - - final streamVideo = locator.get(); - return streamVideo.handleVoipPushNotification( - message.data, - handleMissedCall: false, //<-- Add this flag if you dont want a default missed call notification handling - ); -} -``` - -## iOS and Apple Push Notification Service (APNs) - -For APNs the standard push notifications have to be handled separately of VoIP notifications. When APN push provider is registered for iOS, both VoIP and standard push notifications are send using APN by Stream Video SDK. - -### Registering APN device token - -First you need to register APN device token as it is separate from the VoIP token (registered out-of-the-box by the Stream Video SDK). To do this just set `registerApnDeviceToken` to true when initializing `StreamVideo` instance: - -```dart -StreamVideo( - apiKey, - user: user, - pushNotificationManagerProvider: StreamVideoPushNotificationManager.create( - iosPushProvider: const StreamVideoPushProvider.apn( - name: 'flutter-apn', - ), - androidPushProvider: const StreamVideoPushProvider.firebase( - name: 'flutter-firebase', - ), - pushParams: const StreamVideoPushParams( - appName: kAppName, - ios: StreamIOSParams(iconName: 'IconMask'), - ), - registerApnDeviceToken: true, // <--- Add this line - ), -); -``` - -### Handling standard push notifications - -Next, you need to handle the push notifications in your app. - -To do this, you need to add the following code to your `AppDelegate.swift` file: - -```swift -@objc class AppDelegate: FlutterAppDelegate { -override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - - // Register for push notifications. - StreamVideoPKDelegateManager.shared.registerForPushNotifications() // <--- Add will only handle VoIP notifications - UNUserNotificationCenter.current().delegate = self // <--- Add this line to handle standard push notifications - - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } - -// This method will be called when notification is received -override func userNotificationCenter(_ center: UNUserNotificationCenter, - willPresent notification: UNNotification, - withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { - let streamDict = notification.request.content.userInfo["stream"] as? [String: Any] - if(streamDict?["sender"] as? String != "stream.video") { - return completionHandler([]) - } - - if #available(iOS 14.0, *) { - completionHandler([.list, .banner, .sound]) - } else { - completionHandler([.alert]) - } -} -} -``` - -If you want to handle the notification tap event, for example to navigate to the call screen when you `notify` about it, you can add the following code to your `AppDelegate.swift` file: - -```swift -// This method will be called when notification is tapped -override func userNotificationCenter(_ center: UNUserNotificationCenter, - didReceive response: UNNotificationResponse, - withCompletionHandler completionHandler: @escaping () -> Void) { - - let streamDict = response.notification.request.content.userInfo["stream"] as? [String: Any] - if(streamDict?["sender"] as? String != "stream.video") { - return; - } - - if(streamDict?["type"] as? String == "call.notification") { - let callCid = streamDict?["call_cid"] as? String - print("Call notification received with call cid: \(callCid)") - //Navigate to call, for example implementing method channel - } - - completionHandler() -} -``` - -### Push notification permission - -Remember, that in order to receive push notifications, you need to ask the user for relevant permission. One way of doing it is using [permission_handler](https://pub.dev/packages/permission_handler) plugin. - -```dart -Permission.notification.request(); -``` \ No newline at end of file diff --git a/docusaurus/docs/Flutter/05-advanced/10-manual-video-quality-selection.mdx b/docusaurus/docs/Flutter/05-advanced/10-manual-video-quality-selection.mdx deleted file mode 100644 index 16962f570..000000000 --- a/docusaurus/docs/Flutter/05-advanced/10-manual-video-quality-selection.mdx +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Manual Video Quality Selection -slug: /manual-video-quality-selection -sidebar_position: 10 -description: Learn how to manually select the incoming video quality in the Stream Video Flutter SDK. ---- - -By default, our SDK chooses the incoming video quality that best matches the size of a video element for a given participant. It makes less sense to waste bandwidth receiving Full HD video when it's going to be displayed in a 320 by 240 pixel rectangle. - -However, it's still possible to override this behavior and manually request higher resolution video for better quality, or lower resolution to save bandwidth. It's also possible to disable incoming video altogether for an audio-only experience. - -## Overriding Preferred Resolution - -To override the preferred incoming video resolution, use the `call.setPreferredIncomingVideoResolution` method: - -```dart -await call.setPreferredIncomingVideoResolution(VideoResolution(width: 640, height: 480)); -``` - -:::note -Actual incoming video quality depends on a number of factors, such as the quality of the source video, and network conditions. Manual video quality selection allows you to specify your preference, while the actual resolution is automatically selected from the available resolutions to match that preference as closely as possible. -::: - -It's also possible to override the incoming video resolution for only a selected subset of call participants. The `call.setPreferredIncomingVideoResolution()` method optionally takes a list of participant session identifiers as its optional argument. Session identifiers can be obtained from the call participant state: - -```dart -final [first, second, ..._] = call.state.value.otherParticipants; - -// Set preferred incoming video resolution for the first two participants only: -await call.setPreferredIncomingVideoResolution( - VideoResolution(width: 640, height: 480), - sessionIds: [first.sessionId, second.sessionId], -); -``` - -Calling this method will enable incoming video for the selected participants if it was previously disabled. - -To clear a previously set preference, pass `null` instead of resolution: - -```dart -// Clear resolution preference for selected participants: -await call.setPreferredIncomingVideoResolution( - null, - sessionIds: [ - participant.sessionId, - ], -); -// Clear resolution preference for all participants: -await call.setPreferredIncomingVideoResolution(null); -``` - -## Disabling Incoming Video - -To completely disable incoming video (either to save data, or for an audio-only experience), use the `call.setIncomingVideoEnabled()` method: - -```dart -await call.setIncomingVideoEnabled(false); -``` - -To enable incoming video again, pass `true` as an argument: - -```dart -await call.setIncomingVideoEnabled(true); -``` - -Calling this method will clear the previously set resolution preferences. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/05-advanced/11-session-timers.mdx b/docusaurus/docs/Flutter/05-advanced/11-session-timers.mdx deleted file mode 100644 index e6f512769..000000000 --- a/docusaurus/docs/Flutter/05-advanced/11-session-timers.mdx +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: Session Timers -slug: /session-timers -sidebar_position: 11 -description: Learn how to limit the maximum duration of a call in the Stream Video Flutter SDK. ---- - -A session timer allows you to limit the maximum duration of a call. The duration [can be configured](https://getstream.io/video/docs/api/calls/#session-timers) for all calls of a certain type, or on a per-call basis. When a session timer reaches zero, the call automatically ends. - -## Creating a call with a session timer - -Let's see how to create a single call with a limited duration: - -```dart -final call = client.makeCall(callType: StreamCallType.defaultType(), id: 'REPLACE_WITH_CALL_ID'); -await call.getOrCreate( - limits: const StreamLimitsSettings( - maxDurationSeconds: 3600, - ), -); -``` - -This code creates a call with a duration of 3600 seconds (1 hour) from the time the session is starts (a participant joins the call). - -After joining the call with the specified `maxDurationSeconds`, you can examine a call state's `timerEndsAt` field, which provides the timestamp when the call will end. When a call ends, all participants are removed from the call. - -```dart -await call.join(); -print(call.state.value.timerEndsAt); -``` - -## Extending a call - -​You can also extend the duration of a call, both before or during the call. To do that, you should use the `call.update` method: - -```dart -final duration = - call.state.value.settings.limits.maxDurationSeconds! + 60; - -call.update( - limits: StreamLimitsSettings( - maxDurationSeconds: duration, - ), -); -``` - -If the call duration is extended, the `timerEndsAt` is updated to reflect this change. Call participants will receive the `call.updated` event to notify them about this change. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/05-advanced/_category_.json b/docusaurus/docs/Flutter/05-advanced/_category_.json deleted file mode 100644 index 0e23d1f4f..000000000 --- a/docusaurus/docs/Flutter/05-advanced/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Advanced Guides" -} diff --git a/docusaurus/docs/Flutter/06-ui-cookbook/01-overview.mdx b/docusaurus/docs/Flutter/06-ui-cookbook/01-overview.mdx deleted file mode 100644 index 70c982c23..000000000 --- a/docusaurus/docs/Flutter/06-ui-cookbook/01-overview.mdx +++ /dev/null @@ -1,95 +0,0 @@ -# What Are UI Cookbooks? -Stream UI components are highly customizable and allow you to fully customize styles to your taste. This UI Cookbook will walk you through how to customize each component in your video call. - -export const CookbookCard = ({ title, children }) => ( -
  • -

    {title}

    - {children} -
  • -); - -This cookbook aims to show you how to build your own UI elements for video calling. - -### Video Calls & Ringing - -
    -
      - - - - - - - - - - - - - - - - - - -
    -
    - -### Audio rooms & Livestreams - -
    -
      - - - - - - -
    -
    - -### Small Components - -
    -
      - - - - - - - - - -
    -
    diff --git a/docusaurus/docs/Flutter/06-ui-cookbook/02-participant-list.mdx b/docusaurus/docs/Flutter/06-ui-cookbook/02-participant-list.mdx deleted file mode 100644 index 8eeb22fde..000000000 --- a/docusaurus/docs/Flutter/06-ui-cookbook/02-participant-list.mdx +++ /dev/null @@ -1,303 +0,0 @@ -# Participant List - -**Participant List** is the most important view for any video-related application. While UI Components package provides customizable [CallParticipants](../04-ui/03-components/02-participants/02-call-participants.mdx) component, you might -decide to develop your own view if the default's view customization level is not enough for you or you would rather have full control over the view. - -The guide will go step-by-step through how to create a custom participant list using Stream Video LLC (Low-Level-Client). We'll cover the following topics: -1. How to connect a user to the call. -2. How to access and observe the call state. -3. How to render the participant list. -4. How to render a mute state for each participant. -5. How to highlight the dominant speaker. - -By the end of this guide, your custom screen will look like this: - -|![Final Result](../assets/ui_cookbook_participant_list_final_result.png)| -|---| - -The guide assumes you know how to initialize the SDK and connect the user. Make sure to check [Introduction](../01-setup/01-introduction.mdx) if you want to know how to start. - -Let's see how to implement this. - -## Connecting to the call and observing the call state - -Before building the actual view, let's take a look on how we can obtain and connect to the call using the Low-Level-Client. This needs to be done in two steps: - -1. Get the call object using the `StreamVideo` class: - -```dart - final call = StreamVideo.instance.makeCall(callType: StreamCallType(), id: 'Your-call-ID'); - await call.getOrCreate(); -``` - -2. Connect the current user to the call obtained before: - -```dart - call.join(); -``` - -That's it. From that point, we can start listening to call state updates. The easiest way to do that is by listening to the stream that can be accessed from the `Call` object: - -```dart - final _subscription = widget.call.state.listen((callState) { - - }); -``` - -The `CallState` class contains all of the information about the current call, for example: a list of participants, status, capabilities, etc. -You can find more information about the call state itself [here](../03-core-concepts/03-call-state.mdx) - -:::note -Remember about disposing the subscription if it's no longer needed. -::: - -Let's combine the snippets presented above into a single `StatefulWidget`: - -```dart -class ParticipantListScreen extends StatefulWidget { - const ParticipantListScreen({super.key, required this.call}); - - final Call call; - - @override - State createState() => _ParticipantListScreenState(); -} - -class _ParticipantListScreenState extends State { - - late CallState _callState; - StreamSubscription? _subscription; - - @override - void initState() { - widget.call.join(); - - _callState = widget.call.state.value; - _subscription = widget.call.state.listen((callState) { - setState(() { - _callState = callState; - }); - }); - - super.initState(); - } - - @override - void dispose() { - _subscription?.cancel(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Container(); - } -} -``` - -Note that the `call` object is provided through the constructor in order not to unnecessarily recreate objects during hot reload. - -## Implementing custom participants list - -It's time to use the data and render call participants. As mentioned above, we'll rely on the information provided by the `callState`, and more specifically - `callState.callParticipants`. But before rendering the list, let's start with a single participant view: - -```dart -class CallParticipantWidget extends StatelessWidget { - const CallParticipantWidget({super.key, required this.callParticipantState}); - - final CallParticipantState callParticipantState; - - @override - Widget build(BuildContext context) { - return CircleAvatar( - radius: 48, - backgroundImage: NetworkImage( - callParticipantState.profileImageURL!, - ), - ); - } -} -``` - -The widget above receives a single participant state and renders a circular avatar using `profileImageURL`. - -Now it's time to render all participants using a simple `ListView`: - -```dart -class ParticipantListScreen extends StatefulWidget { - const ParticipantListScreen({super.key, required this.call}); - - final Call call; - - @override - State createState() => _ParticipantListScreenState(); -} - -class _ParticipantListScreenState extends State { - late CallState _callState; - StreamSubscription? _subscription; - - @override - void initState() { - widget.call.join(); - - _callState = widget.call.state.value; - _subscription = widget.call.state.listen((callState) { - setState(() { - _callState = callState; - }); - }); - - super.initState(); - } - - @override - void dispose() { - _subscription?.cancel(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final callParticipants = _callState.callParticipants; - - return Scaffold( - appBar: AppBar( - title: const Text('Participant List'), - ), - body: _callState.status.isConnected - ? Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Expanded( - flex: 5, - child: ColoredBox(color: Colors.white), - ), - Expanded( - child: ColoredBox( - color: Colors.black87, - child: ListView.separated( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 16, - ), - itemBuilder: (context, index) { - return CallParticipantWidget( - callParticipantState: callParticipants[index], - ); - }, - separatorBuilder: (_, __) => const SizedBox(width: 8), - itemCount: callParticipants.length, - scrollDirection: Axis.horizontal, - ), - ), - ), - ], - ) - : const Center(child: CircularProgressIndicator()), - ); - } -} -``` - -You can note that we are checking if the call is already connected, by checking `_callState.status.isConnected`, before showing the actual participant list. - -That's it. The list is implemented and will be automatically refreshed once the call status changes, for example: when participant joins or leaves. The code above renders the following screen: - -|![Participant List Without Muting](../assets/ui_cookbook_participant_list_without_muting.png)| -|---| - -Now, let's see how we can add more details to our single participant view. - -## Rendering mute status and highlighting dominant speaker - -Let's add more information to the single participant widget, starting from adding information if the participant is muted: - -```dart -class CallParticipantWidget extends StatelessWidget { - const CallParticipantWidget({super.key, required this.callParticipantState}); - - final CallParticipantState callParticipantState; - - @override - Widget build(BuildContext context) { - return Stack( - alignment: Alignment.bottomRight, - children: [ - const CircleAvatar( - radius: 48, - backgroundImage: NetworkImage( - callParticipantState.profileImageURL!, - ), - ), - Icon( - callParticipantState.isAudioEnabled - ? Icons.mic_rounded - : Icons.mic_off_rounded, - color: Colors.white, - ) - ], - ); - } -} -``` - -The snippet above utilizes information provided by `callParticipantState` and renders different icons at the bottom right corner based on particular participant audio status. - -You can check the result below: - -|![Participant With Muted Icon](../assets/ui_cookbook_participant_list_mute_icon.png)| -|---| - -As the last step, let's add a blue highlight for the participant who is currently an active speaker. We'll use an [external library](https://pub.dev/packages/avatar_glow) for that purpose: - -Start with adding `avatar_glow: ^2.0.2` to the dependencies in `pubspec.yaml` file. - -Next, let's slightly modify our `CallParticipantWidget`: - -```dart -class CallParticipantWidget extends StatelessWidget { - const CallParticipantWidget({super.key, required this.callParticipantState}); - - final CallParticipantState callParticipantState; - - @override - Widget build(BuildContext context) { - return AvatarGlow( - animate: callParticipantState.isDominantSpeaker, - endRadius: 56, - glowColor: Colors.blue, - child: Stack( - alignment: Alignment.bottomRight, - children: [ - const CircleAvatar( - radius: 48, - backgroundImage: NetworkImage( - callParticipantState.profileImageURL!, - ), - ), - Icon( - callParticipantState.isAudioEnabled - ? Icons.mic_rounded - : Icons.mic_off_rounded, - color: Colors.white, - ) - ], - ), - ); - } -} -``` - -That's all we need. The most important change was wrapping the widget created before with the `AvatarGlow` and starting the animation based on the `callParticipantState.isDominantSpeaker` flag. After this change, you will notice a glow effect around participant who is a dominant speaker: - -|![Participant Dominant Speaker](../assets/ui_cookbook_participant_list_dominant_speaker.png)| -|---| - -Now, you're ready to experiment more and add feature to your custom participants list. Play around with the `CallState` and `CallParticipantState` and as a next step you might want to enhance your view with: - -- Participant name -- Connection quality -- Participant's video track - -and much more. diff --git a/docusaurus/docs/Flutter/06-ui-cookbook/03-permission-requests.mdx b/docusaurus/docs/Flutter/06-ui-cookbook/03-permission-requests.mdx deleted file mode 100644 index c5c674964..000000000 --- a/docusaurus/docs/Flutter/06-ui-cookbook/03-permission-requests.mdx +++ /dev/null @@ -1,51 +0,0 @@ -# Permission Requests -During a call, participants can have different capabilities and permissions. This is very common for use cases such as e-learning or large conference calls where the call organizer may want to enable additional controls to prevent users from speaking during large calls or control when users are allowed to broadcast their video. - -In this sample, we will take a closer look at the ways in which users can listen, request, and act on permission requests. For more information on the full moderation and permissions of [Stream Video](https://getstream.io/video/), please see our full guide [here](https://getstream.io/video/docs/flutter/permission-and-moderation/). - -## Listening for new permission requests -When a user requests a new capability during a call, the `onPermissionRequest` function is triggered on the `Call` object. This function receives an object containing the requested permissions list and an object representing the `CallUser` who made the request. - -```dart -@override - void initState() { - super.initState(); - /// The [onPermissionRequest] handler can be used to be notified of new requests from users in the call. - /// [CoordinatorCallPermissionRequestEvent] contains the user requesting permissions along with a list - /// containing the different capabilities they would like granted. - widget.call.onPermissionRequest = - (CoordinatorCallPermissionRequestEvent permissionRequestEvent) { - final uid = permissionRequestEvent.user.id; - - /// For more complex applications, a user may request one or more permission at the same time. In those cases, - /// the full range of permissions can be retrieved from the `permissions` list. - final permission = permissionRequestEvent.permissions; - }; - } -``` - -The `CoordinatorCallPermissionRequestEvent` also includes: - -- `callCid` - ID of the current call -- `createdAt` - Timestamp of when the user made the permission request -- `permissions` - List of call permissions requested by the user -- `user` - Object representing the user making the current request - -## Responding to permission requests -Should the call admins wish to grant the request permissions, they can easily do so by calling `grantPermissions` on the `Call` object. The user ID, along with the list of permissions requested, must be supplied to the function. - -Below is a simple example of allowing a user to speak during a call: - -```dart -/// Once a permission request is received, it can be granted using [grantPermissions] or revoked using [revokePermissions] - Future grantSpeakingPermission(String userID) async { - await widget.call.grantPermissions( - userId: userID, - permissions: [CallPermission.sendAudio], - ); - } -``` - -This workflow can easily be adapted to fit your application’s UI. For example, a very common use case for handling permission requests is to show a modal of all permission requests and a button to either allow or cancel the request. - -For a full example, please see our code on [GitHub](https://github.com/GetStream/flutter-video-samples). \ No newline at end of file diff --git a/docusaurus/docs/Flutter/06-ui-cookbook/04-chat-with-video.mdx b/docusaurus/docs/Flutter/06-ui-cookbook/04-chat-with-video.mdx deleted file mode 100644 index 8fdd900b5..000000000 --- a/docusaurus/docs/Flutter/06-ui-cookbook/04-chat-with-video.mdx +++ /dev/null @@ -1,532 +0,0 @@ -# Building Chat Apps With Video Support - -One of the most common chat app use cases is having a chat feature in your app that allows users to engage in audio and video communication. This direct integration allows for a simple transition between text and images to more complex media. - -Stream supports this use case, out-of-the-box. In this guide, you'll walk through all the steps required to integrate our Chat and Video Flutter SDKs into a cohesive whole. You'll cover the following: - -* Adding Stream dependencies. -* Creating Stream clients. -* Authenticating Chat and Video users. -* Building custom Call attachments and "Start Call" UI. - -By the end of this guide, your app will look like this: - -|![Final Result](../assets/chat_with_video_final_result.png)| -|---| - -You'll have the ability to create messaging conversations, in which you can start calls as a custom attachment. Anyone in the chat will then be notified accordingly and can join the call. - -Let's see how to implement this. - -## Creating the project - -The easiest way to get a project working is using one of our [Starter Kits](https://github.com/GetStream/stream-video-flutter/tree/main/examples/chat_with_video). Within the `chat_with_video` directory, open `chat_with_video_starter` in your IDE. - -> **Note**: Within the `chat_with_video` parent, there is a `chat_with_video_final` project that contains the final code for this guide. You can skip the starter kit and open that project instead if you want to see the finished solution. - -Run `flutter pub get` to install the dependencies declared in `pubspec.yaml`: - -```yaml title="/pubspec.yaml" -dependencies: - flutter: - sdk: flutter - - # Stream Chat SDK - stream_chat_flutter: ^latest - - # Stream Video SDK - stream_video_flutter: ^latest -``` - -You'll be integrating two SDKs - Video and Chat. In the snippet above we declared dependencies for both of them. - -The project already has a few screens set up for you with TODO items that you'll fill in later. Run the project and you should see the Login screen, followed by a blank Home screen after you select a user. - -| Login Screen | Home Screen | -|-------------------------------------------------------------|--------------------------------------------------------------| -| ![Login Screen](../assets/chat_with_video_login_screen.png) | ![Home Screen](../assets/chat_with_video_home_screen.png) | - -The pre-baked code contains all the logic that is not related to Stream, so that you can focus solely on integrating our two SDKs. We recommend exploring the project to learn how to navigate it and what each part of the predefined code does. Some of the notable functionality in the starter kit contains: - -- `main.dart` contains an entry point for our application. -- `app_config.dart` contains sample users, with Chat and Video tokens prepared. -- `login_screen.dart`, `channel_list_screen.dart` and `channel_screen.dart` contain screens for a default messaging app navigation. Most of these are empty for now, you'll fill them in. -- `call_attachment.dart` contains a custom attachment that users will use to join a call. - -Now that you have an overview of the starter project, let's start integrating the SDKs. - -## Integrating the Chat SDK - -The first step of integrating our [Stream Chat SDK](https://getstream.io/chat/flutter/tutorial/) is initializing the `StreamChatClient`. You'll do that in the `main.dart` file, as it's recommended to initialize the client as soon as your app is launched. On top of that, you'll have to log in as a user, to fetch their information and conversations. - -### Creating the Client - -Open the `main.dart` file and replace the Stream Chat SDK initialization section with the following: - -```dart title="/lib/main.dart" -final client = StreamChatClient( - "tp8sef43xcpc", - logLevel: Level.INFO, -); -``` - -Then, you need to pass the client to `MyApp` widget and wrap the client into `StreamChat` widget: - -```dart title="/lib/main.dart" -class MyApp extends StatelessWidget { - const MyApp({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - Widget build(BuildContext context) { - return MaterialApp( - builder: (context, child) => StreamChat( - client: client, - child: child, - ), - home: LoginScreen(), - ); - } -} -``` - -The final result should look like this: - -```dart title="/lib/main.dart" -import 'package:chat_with_video_starter/screen/login_screen.dart'; -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -void main() { - final client = StreamChatClient( - "tp8sef43xcpc", - logLevel: Level.INFO, - ); - - /// TODO: Initialize Stream Video SDK. - - runApp(MyApp(client: client)); -} - -class MyApp extends StatelessWidget { - const MyApp({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - Widget build(BuildContext context) { - return MaterialApp( - builder: (context, child) => StreamChat( - client: client, - child: child, - ), - home: LoginScreen(), - ); - } -} -``` - -There are several important things to notice here: - -- The Stream Chat API client is initialized with your API Key. -- The client is then passed to the top-level `StreamChat` inherited widget that will provide the client to all the child widgets. - -With this client initialization, you can proceed to log in a user when you choose them on the login screen. - -### Logging in a User - -Open `login_screen.dart` and replace `_connectChatUser` with the following: - -```dart title="/lib/screen/login_screen.dart" -Future _connectChatUser(BuildContext context, SampleUser user) async { - final chatClient = StreamChat.of(context).client; - - await chatClient.connectUser( - user.toChatUser(), - user.chatToken, - ); -} -``` - -On the login screen, when you select a user, you call `_connectChatUser`. This lets you set up the user for Chat SDK. In this case, you're doing the following: - -1. You obtain the `StreamChatClient` instance from `StreamChat`. -2. You map a `SampleUser` into a `User` object from the Chat SDK. -3. You pass in the `user` to `chatClient.connectUser()`. - -To finish up, you can add the logging out counterpart, by replacing `_disconnectChatUser` with the following: - -```dart title="/lib/screen/login_screen.dart" -Future _disconnectChatUser(BuildContext context) async { - final chatClient = StreamChat.of(context).client; - - await chatClient.disconnectUser(); -} -``` - -With all this, you'll be able to log in and log out any user from our predefined data set. The next step is to display their conversations. - -### Implementing Channel List Screen - -There isn't much to the channel list screen - it'll show a list of `Channel`s the user is a member of and let them open those `Channel`s. It'll also feature a custom header to allow the user to log out at will. - -Most of the navigation functionality, like opening a `Channel` and logging out is already there, you just need to use our Flutter UI Components to implement the UI. - -Open `channel_list_screen.dart`. Add the following code to `_ChannelListScreenState`, to initialize the `StreamChannelListController`, that'll help you load, fetch and display the required data: - -```dart title="/lib/screen/channel_list_screen.dart" -late final _listController = StreamChannelListController( - client: StreamChat.of(context).client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], -); - -@override -void dispose() { - _listController.dispose(); - super.dispose(); -} -``` - -While this is a simple piece of code, there are a few steps to analyze: - -1. You obtain the `StreamChatClient` instance from `StreamChat`. -2. The controller requires the `StreamChatClient` instance to communicate with the API, a `channelStateSort` to define the order of the `Channel`s and `filter` to specify which `Channel`s we want to fetch. -3. Finally, we need to dispose the controller in the `dispose()` method. - -With the `StreamChannelListController` ready, add the following code to the `build()` method. Specifically, you'll add a header that will allow the user to log out and a component that shows a list of channels and lets you open the `ChannelScreen`. - -```dart title="/lib/screen/channel_list_screen.dart" -@override -Widget build(BuildContext context) { - return Scaffold( - appBar: StreamChannelListHeader( - titleBuilder: (context, status, client) { - return Text( - "Chat with Video", - style: StreamChatTheme.of(context).textTheme.headlineBold, - ); - }, - actions: [ - IconButton( - icon: const Icon( - color: Colors.black, - Icons.logout, - ), - onPressed: () async => widget.onLogout.call(), - ), - ], - ), - body: StreamChannelListView( - controller: _listController, - onChannelTap: (channel) { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) { - return StreamChannel( - channel: channel, - child: ChannelScreen(), - ); - }, - ), - ); - }, - ), - ); -} -``` - -The final result should look like this: - -```dart title="/lib/screen/channel_list_screen.dart" -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -import 'channel_screen.dart'; - -class ChannelListScreen extends StatefulWidget { - const ChannelListScreen({Key? key, required this.onLogout}) : super(key: key); - - final VoidCallback onLogout; - - @override - State createState() => _ChannelListScreenState(); -} - -class _ChannelListScreenState extends State { - late final _listController = StreamChannelListController( - client: StreamChat.of(context).client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _listController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: StreamChannelListHeader( - titleBuilder: (context, status, client) { - return Text( - "Chat with Video", - style: StreamChatTheme.of(context).textTheme.headlineBold, - ); - }, - actions: [ - IconButton( - icon: const Icon( - color: Colors.black, - Icons.logout, - ), - onPressed: () async => widget.onLogout.call(), - ), - ], - ), - body: StreamChannelListView( - controller: _listController, - onChannelTap: (channel) { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) { - return StreamChannel( - channel: channel, - child: ChannelScreen(), - ); - }, - ), - ); - }, - ), - ); - } -} -``` - -There are only a few lines of code here that let you set up an entire screen and lots of functionality: - -1. You add the `StreamChannelListHeader` component that displays a title and allows for a few handlers and widget builders. In this case, you override the `actions` section to show a button used to log out the user from the app. -2. Using the `_listController`, you render a `StreamChannelListView`, which shows a list of `Channel`s. Overriding `onChannelTap`, lets you set up functionality when a user selects any `Channel`. In your case, you navigate to `ChannelScreen`. -3. Notice how the selected channel is provided to `ChannelScreen` via the `StreamChannel` inherited widget. - -Build and run the app and you should be able to log in or out with a user, as well as see and open the `Channel`s they're a part of. - -| ![Channels Screen](../assets/chat_with_video_channel_list.png) | -|------------------------------------------------------------------| - -The next step to integrating the Chat SDK to replicate a chat-first-app that allows video calls, is to display the selected conversations and integrate custom attachments that render created calls. - -### Adding Messaging Functionality - -You're able to open the `ChannelScreen`, but it's fully empty at the moment. Let's change that. Open `ChannelScreen` and at the very top of the class, add the UI code: - -```dart title="/lib/screen/channel_screen.dart" -@override -Widget build(BuildContext context) { - return Scaffold( - appBar: StreamChannelHeader( - actions: [ - IconButton( - icon: const Icon( - Icons.call_rounded, - color: Colors.black, - ), - onPressed: () async => _startCall(context), - ), - ], - ), - body: Column( - children: [ - Expanded( - child: StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - customAttachmentBuilders: _customAttachmentBuilders()); - }, - ), - ), - StreamMessageInput(), - ], - ), - ); -} -``` - -The block of code here is mostly straightforward, as you're just composing a `ChannelScreen`, with some custom UI. Let's go over it: - -1. You add a `topBar` to the `Scaffold`, using `StreamChannelHeader`. Overriding the `actions` allows you to set custom UI and behavior when the user interacts with that UI component, such as creating a Call. -2. You add `StreamMessageListView`, with a list of `customAttachmentBuilders`. This will be important, as you'll serve the `Channel` with custom Call attachments that let users join a video call. -3. Finally, you add `StreamMessageInput` with no special customization. - -Build and run the app now and try opening a channel. You should see something like this: - -|![Channel Screen](../assets/chat_with_video_channel_screen.png)| -|---|---| - -You have a full integration of chat features in your app now. You can see channels, open them, send messages and attachments, start threads and much more. If you notice that some of the messages appear to be missing, that's because our SDK is trying to render custom Call attachments, but it doesn't yet know how. - -For that to work, you need to add custom attachment builders to the SDK. There is already a custom attachment builder prepared for you, you just need to pass it to `StreamMessageListView`. - -### Supporting Custom Attachments - -Open the `call_attachment.dart` file. Explore it to familiarize yourself with the logic behind the UI it shows and the way it allows users to join the call using the following snippet: - -```dart title="/lib/screen/attachment/call_attachment.dart" -Future _joinCall(BuildContext context, String cid) async { - final parts = cid.split(':'); - final type = StreamCallType.fromString(parts[0]); - final id = parts[1]; - - final call = StreamVideo.instance.makeCall(type: type, id: id); - await call.join(); - return call; -} -``` - -It consumes the data stored in the custom attachment to join a call. Right now, the `StreamVideo` instance is not yet set up, as you'll do that in the final step of the guide. - -To add the custom attachment builder, open the `channel_screen.dart` file and replace the `_customAttachmentBuilders` method with the following: - -```dart title="/lib/screen/channel_screen.dart" -Map _customAttachmentBuilders() { - return { - 'custom': (context, message, attachments) { - return WrapAttachmentWidget( - attachmentWidget: CallAttachment( - message: message, - attachment: attachments.first, - ), - attachmentShape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ); - } - }; -} -``` - -Build and run the app now and your custom Call attachments should render properly. - -![Final Result](../assets/chat_with_video_final_result.png) - -Great, you're ready to join calls. But for that, you need to integrate the Stream Video Flutter SDK. - -## Integrating the Video SDK - -To successfully connect to a Call, you need to use its `callCid` to get the detailed information and join it. The internal process of joining a Call has several steps, such as measuring the latency and choosing the best server to connect through, but all you care about now is the trigger to join a Call and show the corresponding UI. - -Firstly, you need to initialize the Video client, aptly called `StreamVideo`. - -### Initializing StreamVideo and logging in a User - -You're now ready to log in the user and connect to a call when tapping on the custom attachment or header action. - -For the login aspect of `StreamVideo`, there's not much to think about. The `StreamVideo` client is tied to a user instance. You cannot access any potential Calls or join an audio/video call, unless you're logged in. It's a server requirement and it makes things easy to think about. - -Open the `login_screen.dart` file and replace the `_connectVideoUser` code with the following: - -```dart title="/lib/screen/login_screen.dart" -Future _connectVideoUser(SampleUser user) async { - var client = StreamVideo( - "us83cfwuhy8n", - user: user.toVideoUser(), - userToken: user.videoToken, - ); - - await client.connect(); -} -``` - -It's very simple in what it does: - -1. You initialise `StreamVideo` using your API key and pass along the user you want to connect. -2. You call the `connect()` function to connect the video client. -3. The `StreamVideo` client created here is now accessible using `StreamVideo.instance` anywhere in your app. - -With all of this, your attachments will be able to hit the Video API endpoints to join a call. - -To finish up, you can add the logging out counterpart, by replacing `_disconnectVideoUser` with the following: - -```dart title="/lib/screen/login_screen.dart" -Future _disconnectVideoUser() async { - final videoClient = StreamVideo.instance; - - await videoClient.disconnect(); -} -``` - -### Allowing Users To Start Calls - -Open the `channel_screen.dart` file and find `_startCall()`. Within it, add the following code: - -```dart title="/lib/screen/channel_screen.dart" -void _startCall(BuildContext context) async { - final currentUser = StreamChat.of(context).currentUser; - final channel = StreamChannel.of(context).channel; - - final call = StreamVideo.instance.makeCall( - id: 'call${Random().nextInt(10000)}', - type: "default", - ); - - await call.getOrCreate( - memberIds: [], - ringing: false, - ); - - channel.sendMessage( - Message( - attachments: [ - Attachment( - type: "custom", - authorName: currentUser?.name ?? "", - uploadState: UploadState.success(), - extraData: { - "callCid": call.callCid, - }, - ) - ], - ), - ); -} -``` - -This snippet is larger than the previous integration steps, but it packs a few things to keep in mind when creating a Call: - -1. You are able to `makeCall()` by passing in a Call ID and its `type`. You can then use `call.getOrCreate()` if you want to create a ringing call and add `memberIds`. For simplicity, you' will create **meeting calls**, which don't require any initial members or ringing. -2. If the API call is successful, you can proceed to build the Call attachment. If the API call fails, you can show custom UI to the user, but in this case we'll just ignore that case. -3. To build the `Attachment`, you use its constructor, which lets you define the type of the `Attachment`, its author and any `extraData` you might need to render the UI. In this case, you pass in the `call.callCid` used to show the UI in the list. -4. Finally, when the attachment is ready, you can build a new `Message` and pass in your `customAttachment`. By calling `channel.sendMessage()`, you create a new message in the channel, with the details required to join the Call. - -You could've approached this logic differently and shown a special dialog to the user for the call creation, give them more options for customization, like who to invite and similar. But for this basic use case of Chat + Video, you'll just create a simple call that's public in the Channel. - -Now, you're fully ready to start and enjoy the Chat + Video experience. Build and run the app, log in and join any call attachment, or create a new call and join like that. - -|![Call Screen](../assets/chat_with_video_call_screen.png)| -|---| - -Play around with the controls, the default `StreamActiveCall` and the SDK offer the following options: - -* Enable or disable audio and video -* Switch to speakerphone -* Flip your camera -* Leave the call -* Observe participants and invite new people to the call - -And much more. You've implemented everything you need to achieve a good Chat + Video use case. diff --git a/docusaurus/docs/Flutter/06-ui-cookbook/05-watching-a-livestream.mdx b/docusaurus/docs/Flutter/06-ui-cookbook/05-watching-a-livestream.mdx deleted file mode 100644 index 1784671cc..000000000 --- a/docusaurus/docs/Flutter/06-ui-cookbook/05-watching-a-livestream.mdx +++ /dev/null @@ -1,120 +0,0 @@ -# Watching a Livestream - -This sample walks you through building advanced UIs for watching a Livestream on Flutter. - -:::note -In this cookbook tutorial, we will assume that you already know how to join a Livestream call. If you haven't familiarized yourself with the **[Livestream Tutorial](https://getstream.io/video/docs/flutter/livestreaming/)** yet, we highly recommend doing so before proceeding with this cookbook. -::: - -To view an HLS stream and benefit from the full experience of selecting different streaming qualities and performing different player actions like muting and unmuting the stream, we recommend using [lecle_yoyo_player](https://pub.dev/packages/lecle_yoyo_player). - -When building for livestreaming, there are a few considerations you need to keep in mind for the UI: - -- UI for when the video isn't loaded yet -- A message to show when the Livestream hasn't started yet -- What to show when the Livestream stopped -- How to indicate when there are connection problems -- Number of participants -- Duration of the call - -## Setting up the UI -To setup our UI for rendering a Livestream, we can use Flutter’s built-in `StreamBuilder` widget for listening to changes in our call state and rendering different UIs based on the stage of our live stream: - -```dart -@override - Widget build(BuildContext context) { - return SafeArea( - child: StreamBuilder( - stream: widget.call.state.valueStream, - initialData: widget.call.state.value, - builder: (context, snapshot) { - final callState = snapshot.data!; - return Stack( - children: [ - if (snapshot.hasData && !callState.isBackstage) - // TODO: Render Video - - if (snapshot.hasData && !callState.isBackstage) - // TODO: Render Participant Count - - if (!snapshot.hasData) - // TODO: Render loading indicator - - if (snapshot.hasData && callState.isBackstage) - // TODO: Display message call is not live - - ], - ); - }, - ), - ); - } -} -``` - -By looking at different properties on our `CallState`, we can render different UIs and messages based on whether the call is live, backstage, or loading. A `Stack` also allows us to add different secondary live stream elements such as a view count above the main UI. - -## Rendering the Livestream -Before running the code below to see the Livestream in action, we recommend going to our [Dashboard](https://dashboard.getstream.io/) and creating a Livestream first since it can be done visually without having to create another instance of the application on the simulator. - -Once a stream is started on the dashboard, the `Livestream ID` can be passed to the `id` parameter for the `Call` object in code. - -![Stream Livestream Dashboard](../assets/cookbook/livestreaming-dashboard.png) - -```dart -@override - Widget build(BuildContext context) { - return SafeArea( - child: StreamBuilder( - stream: widget.call.state.valueStream, - initialData: widget.call.state.value, - builder: (context, snapshot) { - final callState = snapshot.data!; - return Stack( - children: [ - if (snapshot.hasData && !callState.isBackstage) - _buildRender(callState), - if (snapshot.hasData && !callState.isBackstage) - Positioned( - top: 12.0, - left: 12.0, - child: Material( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), - ), - color: Colors.red, - child: Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - 'Viewers: ${callState.callParticipants.length - 1}', - style: const TextStyle( - fontSize: 14, - color: Colors.white, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), - ), - if (snapshot.hasData && (callState.isBackstage)) - const Material( - child: Center( - child: Text('Stream not live'), - ), - ), - if (!snapshot.hasData) - const Center( - child: CircularProgressIndicator(), - ), - ], - ); - }, - ), - ); - } -} -``` - -To view our full list of Video examples, please check out our Flutter Cookbook on [GitHub](https://github.com/GetStream/flutter-video-samples). \ No newline at end of file diff --git a/docusaurus/docs/Flutter/06-ui-cookbook/06-network-quality-indicator.mdx b/docusaurus/docs/Flutter/06-ui-cookbook/06-network-quality-indicator.mdx deleted file mode 100644 index c40f4443a..000000000 --- a/docusaurus/docs/Flutter/06-ui-cookbook/06-network-quality-indicator.mdx +++ /dev/null @@ -1,74 +0,0 @@ -# Network Quality Indicator - -Network quality can impact the video experience a lot. -Therefore, it is always a good idea to display the network quality of the participants in the call. - -## Network quality in a call - -When you are in a call, the network quality for each participant is delivered from the server. -It is available via the `connectionQuality` property from `CallParticipantState`. - -The connection quality property can have the following values: - -```dart -enum SfuConnectionQuality { - unspecified, - poor, - good, - excellent, -} -``` - -By default, it is shown via the `StreamConnectionQualityIndicator` widget: - -```dart -StreamConnectionQualityIndicator( - connectionQuality: participant.connectionQuality, - activeColor: connectionLevelActiveColor, - inactiveColor: connectionLevelInactiveColor, -), -``` - -Additionally, you can customise some aspects of the network quality indicator such as the active/inactive -color as well as the alignment of the network indicator. - -You can do these customisations inside the `StreamCallParticipant` widget: - -```dart -StreamCallContainer( - // ... - callContentBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallContent( - call: call, - callState: callState, - callParticipantsBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallParticipants( - call: call, - participants: callState.callParticipants, - callParticipantBuilder: ( - BuildContext context, - Call call, - CallParticipantState callState, - ) { - return StreamCallParticipant( - call: call, - participant: callState, - connectionLevelActiveColor: Colors.blue, - connectionLevelAlignment: Alignment.bottomRight, - connectionLevelInactiveColor: Colors.white, - ); - }, - ); - }, - ); - }, -) -``` \ No newline at end of file diff --git a/docusaurus/docs/Flutter/06-ui-cookbook/07-audio-volume-indicator.mdx b/docusaurus/docs/Flutter/06-ui-cookbook/07-audio-volume-indicator.mdx deleted file mode 100644 index e3d0a50c9..000000000 --- a/docusaurus/docs/Flutter/06-ui-cookbook/07-audio-volume-indicator.mdx +++ /dev/null @@ -1,52 +0,0 @@ -# Audio Volume Indicator - -The audio indicator provides visual feedback when a user connected to the call is speaking. - -![Audio Indicator](../assets/cookbook/audio-volume-indicator.png) - -You can observe several things about audio in the `CallParticipantState` class such as: - -* Check if the current user is the dominant speaker: `participantState.isDominantSpeaker` -* Check if the current user is speaking: `participantState.isSpeaking` -* Check the audio level of the user: `participantState.audioLevel` - -## Customising the audio volume indicator - -You can change the color of the audio indicator using the `audioLevelIndicatorColor` parameter of the `StreamCallParticipant` widget: - -```dart -StreamCallContainer( - // ... - callContentBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallContent( - call: call, - callState: callState, - callParticipantsBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallParticipants( - call: call, - participants: callState.callParticipants, - callParticipantBuilder: ( - BuildContext context, - Call call, - CallParticipantState participantState, - ) { - return StreamCallParticipant( - call: call, - participant: participantState, - audioLevelIndicatorColor: Colors.teal, - ); - }, - ); - }, - ); - }, -), -``` diff --git a/docusaurus/docs/Flutter/06-ui-cookbook/08-participant-label.mdx b/docusaurus/docs/Flutter/06-ui-cookbook/08-participant-label.mdx deleted file mode 100644 index ac3c3197b..000000000 --- a/docusaurus/docs/Flutter/06-ui-cookbook/08-participant-label.mdx +++ /dev/null @@ -1,54 +0,0 @@ -# Participant Labels - -Showing participant info is an important part of the calling experience, and can have different design variations. -By default, the SDK shows the name of the participant with white color, in a black `DecoratedBox` with opacity 0.5. -Additionally, it also displays an audio indicator at the end by default. - -![Participant Label](../assets/cookbook/participant_label.png) - -## Customising the participant label - -You can change the `TextStyle` and alignment of the label using the `participantLabelTextStyle` and `participantLabelAlignment` parameters -of the `StreamCallParticipant` widget respectively: - -```dart -StreamCallContainer( - // ... - callContentBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallContent( - call: call, - callState: callState, - callParticipantsBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallParticipants( - call: call, - participants: callState.callParticipants, - callParticipantBuilder: ( - BuildContext context, - Call call, - CallParticipantState participantState, - ) { - return StreamCallParticipant( - call: call, - participant: participantState, - participantLabelAlignment: Alignment.centerLeft, - participantLabelTextStyle: const TextStyle( - fontWeight: FontWeight.bold, - ), - ); - }, - ); - }, - ); - }, -), -``` - - diff --git a/docusaurus/docs/Flutter/06-ui-cookbook/09-user-avatar.mdx b/docusaurus/docs/Flutter/06-ui-cookbook/09-user-avatar.mdx deleted file mode 100644 index f1f607ca6..000000000 --- a/docusaurus/docs/Flutter/06-ui-cookbook/09-user-avatar.mdx +++ /dev/null @@ -1,85 +0,0 @@ -# User Avatar - -User avatars on video calling screens are important for identifying users, creating a sense of presence, and expressing personality. -As such, it is important to be able to customise user avatars according to your app specifications. - -![User Avatar](../assets/cookbook/user-avatar.png) - -## Customising the user avatar - -The user avatar can be modified via the `userAvatarTheme` parameter of the `StreamCallParticipant` widget: - -```dart -StreamCallContainer( - // ... - callContentBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallContent( - call: call, - callState: callState, - callParticipantsBuilder: ( - BuildContext context, - Call call, - CallState callState, - ) { - return StreamCallParticipants( - call: call, - participants: callState.callParticipants, - callParticipantBuilder: ( - BuildContext context, - Call call, - CallParticipantState participantState, - ) { - return StreamCallParticipant( - call: call, - participant: participantState, - userAvatarTheme: StreamUserAvatarThemeData(), - ); - }, - ); - }, - ); - }, -), -``` - -### Customising size of the avatar - -You can change the size of the user avatar on the screen by providing it `BoxConstraints` using the constraints parameter. -The default value of the constraints is `BoxConstraints.tightFor(height: 40, width: 40)`. - -```dart -StreamUserAvatarThemeData( - constraints: const BoxConstraints.tightFor( - height: 50, - width: 50, - ), -), -``` - -### Customising border radius of the avatar - -You can change the border radius of the user avatar using the `borderRadius` parameter. -The default value for border radius is `20` units. - -```dart -StreamUserAvatarThemeData( - borderRadius: const BorderRadius.all(Radius.circular(25)), -), -``` - -### Changing the style of initials displayed - -If the user does not have an image to be displayed, initials of the user are displayed instead. -To change the style of these initials, you can use the `initialsTextStyle` parameter: - -```dart -StreamUserAvatarThemeData( - initialsTextStyle: TextStyle( - fontWeight: FontWeight.bold, - ), -), -``` diff --git a/docusaurus/docs/Flutter/06-ui-cookbook/10-reactions.mdx b/docusaurus/docs/Flutter/06-ui-cookbook/10-reactions.mdx deleted file mode 100644 index f2a2ff787..000000000 --- a/docusaurus/docs/Flutter/06-ui-cookbook/10-reactions.mdx +++ /dev/null @@ -1,76 +0,0 @@ -# Reactions - -Reactions in video calls add a layer of nonverbal communication, adding engagement and enhancing -the overall experience. They are a great way for users to communicate even when on mute. - -![User Reaction](../assets/cookbook/reaction_user.png) - -The Flutter SDK for Stream Video has inbuilt support for displaying reactions as well as reaction -controls to add reactions for a user. - -## Reaction Control - -The `AddReactionOption` is the call control responsible for adding reactions to a video call. - -![Add Reaction Option](../assets/cookbook/add_reaction_option.png) - -You can add the control to your control bar by customising the `StreamCallControls` widget: - -```dart -StreamCallContent( - call: call, - callState: state, - callControlsBuilder: (context, call, state) { - return StreamCallControls( - options: [ - ...defaultCallControlOptions( - call: call, - localParticipant: state.localParticipant!, - ), - AddReactionOption( - call: call, - localParticipant: state.localParticipant!, - ), - ], - ); - }, -) -``` - -## Customising Reactions - -The default reactions supplied by the SDK are `like`, `raised-hand`, and `fireworks`. However, you can -replace these with your own reactions via the `CallControlsTheme`: - -```dart -MaterialApp( - theme: ThemeData( - textTheme: GoogleFonts.robotoMonoTextTheme(), - extensions: >[ - lightAppTheme.copyWith( - callControlsTheme: StreamCallControlsThemeData( - callReactions: [ - CallReactionData( - type: 'reaction', - emojiCode: ':like:', - icon: '👍', - ), - CallReactionData( - type: 'raised-hand', - emojiCode: ':raise-hand:', - icon: '✋', - ), - CallReactionData( - type: 'reaction', - emojiCode: ':fireworks:', - icon: '🎉', - ), - // Add your reaction here - ], - ), - ), - ], - ), - // ... -); -``` diff --git a/docusaurus/docs/Flutter/06-ui-cookbook/11-video-fallback.mdx b/docusaurus/docs/Flutter/06-ui-cookbook/11-video-fallback.mdx deleted file mode 100644 index 9d99c3e88..000000000 --- a/docusaurus/docs/Flutter/06-ui-cookbook/11-video-fallback.mdx +++ /dev/null @@ -1,46 +0,0 @@ -# Video Fallback - -Video fallbacks are shown when the user's video track is disabled and ensures all participants are -identifiable in a video calling experience. - -![Video Fallback](../assets/cookbook/video_fallback.png) - -## Adding a video fallback - -When building your own video experience, you may want to customise the widget shown to users when a -video track is disabled. You can do this via the `videoPlaceholderBuilder` parameter of the -`StreamCallParticipant` widget: - -```dart -StreamCallContainer( - call: call, - callConnectOptions: options, - callContentBuilder: (context, call, state) { - return StreamCallContent( - call: call, - callState: state, - callParticipantsBuilder: (context, call, state) { - return StreamCallParticipants( - call: call, - participants: state.callParticipants, - callParticipantBuilder: (context, call, state) { - return StreamCallParticipant( - call: call, - participant: state, - videoPlaceholderBuilder: (context, call, state) { - // Build your placeholder here - return Center( - child: Text( - state.name, - style: TextStyle(fontSize: 32), - ), - ); - }, - ); - }, - ); - }, - ); - }, -), -``` diff --git a/docusaurus/docs/Flutter/06-ui-cookbook/12-call-lobby.mdx b/docusaurus/docs/Flutter/06-ui-cookbook/12-call-lobby.mdx deleted file mode 100644 index abe25be9d..000000000 --- a/docusaurus/docs/Flutter/06-ui-cookbook/12-call-lobby.mdx +++ /dev/null @@ -1,29 +0,0 @@ -# Call Lobby - -Call lobbies pre-stage participants, allowing device checks and fostering a sense of anticipation, -leading to smoother and more focused video meetings. With Stream Video you can create a video experience -with or without a call lobby. - -![Call Lobby](../assets/cookbook/lobby_screen.png) - -## Adding a call lobby in your call flow - -The Flutter SDK for Stream Video provides an inbuilt `StreamLobbyView` widget which makes it effortless to -incorporate a lobby into your video flow. - -The inbuilt widget contains a variety of things required for a call lobby: a preview of the user's video, -controls for video and audio, the users already in the call, and of course, a join call button. - -To do this, first create a call with the appropriate details and pass it along to the `StreamLobbyView` widget: - -```dart -final call = StreamVideo.instance.makeCall(callType: StreamCallType.defaultType(), id: callId); - -StreamLobbyView( - call: call, - onJoinCallPressed: (options) { - // Navigate to your call screen - }, -), -``` - diff --git a/docusaurus/docs/Flutter/06-ui-cookbook/13-transcriptions.mdx b/docusaurus/docs/Flutter/06-ui-cookbook/13-transcriptions.mdx deleted file mode 100644 index 1a788d7f5..000000000 --- a/docusaurus/docs/Flutter/06-ui-cookbook/13-transcriptions.mdx +++ /dev/null @@ -1,17 +0,0 @@ -# Transcriptions - -Enabling your application to provide a transcript for a call can be very useful for your users. We understand though, that this can be a difficult feature to implement/support. - -This is why, the Flutter Video SDK comes with out of the box Transcription support that you can easily manage. - -First thing you can do is access the transcriptions settings as they have been configured from the dashboard. The `mode` property defines the feature's availability with: - -- `available`: the feature is available for your call and can be enabled. - -- `disabled`: the feature is not available for your call. In this case, it's a good idea to "hide" any UI element you have related to transcription. - -- `autoOn`: the feature is available and it will be enabled automatically, once the user is connected on the call. - -Second thing you can do is to start/stop the transcription itself. This can be done by calling the `call.startTranscription()` and `call.stopTranscription()` methods. - -Transcription file is saved whenever you stop the transcription or end the call. You can then access the transcription files by calling the `call.listTranscriptions()` method. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/06-ui-cookbook/14-call-quality-rating.mdx b/docusaurus/docs/Flutter/06-ui-cookbook/14-call-quality-rating.mdx deleted file mode 100644 index b60f708df..000000000 --- a/docusaurus/docs/Flutter/06-ui-cookbook/14-call-quality-rating.mdx +++ /dev/null @@ -1,192 +0,0 @@ -## Call Quality Rating - -In this guide, we are going to show how one can build a call quality rating form on top of our Flutter Video SDK. -It is a good practice to ask your end users about their overall experience after the end of the call or, while being in a call. - -Here is a preview of the component we are going to build: -![Feedback Dialog](../assets/cookbook/feedback_dialog.png) - -## Submit Feedback API - -Our Flutter Video SDK provides an API for collecting this feedback which later can be seen in the call stats section of our dashboard. - -```dart -await call.collectUserFeedback( - rating: // a rating grade from 1 - 5, - reason: // optional reason message, - custom: { - // ... any extra properties that you wish to collect - }, -); -``` - -## Implementation - -One way to ask for feedback is to show a dialog with a rating scale and an optional text field for the user to provide additional comments when they leave the call: - -```dart -StreamCallContainer( - call: widget.call, - onLeaveCallTap: () async { - // Leave the call - await widget.call.leave(); - - // Show the feedback dialog - await showDialog( - context: context, - builder: (BuildContext context) { - return FeedbackWidget(call); - }, - ); - }, - ... -); -``` - -Lets implement a simple widget that will show the feedback form: - -```dart -class FeedbackWidget extends StatefulWidget { - FeedbackWidget( - this.call, { - super.key, - }); - - Call call; - - @override - State createState() => _FeedbackWidgetState(); -} - -class _FeedbackWidgetState extends State { - int value = 0; - TextEditingController textController = TextEditingController(); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Scaffold( - backgroundColor: Colors.transparent, - body: Align( - alignment: Alignment.center, - child: Stack( - children: [ - Container( - padding: - const EdgeInsets.symmetric(horizontal: 32, vertical: 32), - decoration: BoxDecoration( - color: Colors.black87, - borderRadius: BorderRadius.circular(16), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset( - streamVideoIconAsset, - width: 250, - ), - const SizedBox(height: 16), - Text( - 'We Value Your Feedback!', - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.displaySmall, - ), - const SizedBox(height: 4), - Text( - 'Tell us about your video call experience', - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.labelMedium, - ), - const SizedBox(height: 32), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ...[1, 2, 3, 4, 5].map((rating) { - return IconButton( - icon: Icon( - Icons.star, - size: 40, - color: rating <= value - ? AppColorPalette.appGreen - : Colors.grey, - ), - onPressed: () { - setState(() { - value = rating; - }); - }, - ); - }), - ], - ), - const SizedBox(height: 16), - TextField( - controller: textController, - decoration: const InputDecoration( - hintText: 'Tell us more about your experience', - hintStyle: - TextStyle(color: AppColorPalette.secondaryText), - border: OutlineInputBorder(), - ), - textInputAction: TextInputAction.done, - onSubmitted: (value) { - FocusManager.instance.primaryFocus?.unfocus(); - }, - style: const TextStyle(color: Colors.white), - maxLines: 3, - ), - const SizedBox(height: 32), - ElevatedButton( - onPressed: value > 0 - ? () async { - final result = - await widget.call.collectUserFeedback( - rating: value, - reason: textController.text, - ); - - result.fold(success: (_) { - context.pop(); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Thank you for your feedback!'), - ), - ); - }, failure: (error) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - 'Failed to submit feedback: $error'), - ), - ); - }); - } - : null, - child: const Text('Submit Feedback')) - ], - ), - ), - Positioned( - right: 0, - top: 0, - child: IconButton( - icon: const Icon(Icons.close, color: Colors.white), - onPressed: () => context.pop(), - ), - ), - ], - ), - ), - ), - ); - } -} -``` - -This widget will show a dialog with a rating scale and a text field for the user to provide additional comments. When the user submits the feedback, we call the `collectUserFeedback` method on the call object and show a success or error message accordingly. - -That's it. You have successfully implemented a call quality rating dialog using our Flutter Video SDK. You can now ask your users to rate their call experience and collect valuable feedback that can help you improve your video calling experience. diff --git a/docusaurus/docs/Flutter/06-ui-cookbook/_category_.json b/docusaurus/docs/Flutter/06-ui-cookbook/_category_.json deleted file mode 100644 index 3ed345bd0..000000000 --- a/docusaurus/docs/Flutter/06-ui-cookbook/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "UI Cookbook" -} diff --git a/docusaurus/docs/Flutter/assets/advanced_assets/active_call_notification.png b/docusaurus/docs/Flutter/assets/advanced_assets/active_call_notification.png deleted file mode 100644 index 7d4de58a9..000000000 Binary files a/docusaurus/docs/Flutter/assets/advanced_assets/active_call_notification.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/advanced_assets/apns_config.png b/docusaurus/docs/Flutter/assets/advanced_assets/apns_config.png deleted file mode 100644 index 5ecd55af0..000000000 Binary files a/docusaurus/docs/Flutter/assets/advanced_assets/apns_config.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/advanced_assets/background_modes.png b/docusaurus/docs/Flutter/assets/advanced_assets/background_modes.png deleted file mode 100644 index 3aa353b3c..000000000 Binary files a/docusaurus/docs/Flutter/assets/advanced_assets/background_modes.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/advanced_assets/broadcast-extension-config.png b/docusaurus/docs/Flutter/assets/advanced_assets/broadcast-extension-config.png deleted file mode 100644 index 5a55e9592..000000000 Binary files a/docusaurus/docs/Flutter/assets/advanced_assets/broadcast-extension-config.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/advanced_assets/broadcast-extension.png b/docusaurus/docs/Flutter/assets/advanced_assets/broadcast-extension.png deleted file mode 100644 index 8382a2e7b..000000000 Binary files a/docusaurus/docs/Flutter/assets/advanced_assets/broadcast-extension.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/advanced_assets/broadcast-handler-implementation.png b/docusaurus/docs/Flutter/assets/advanced_assets/broadcast-handler-implementation.png deleted file mode 100644 index a4a4e4f00..000000000 Binary files a/docusaurus/docs/Flutter/assets/advanced_assets/broadcast-handler-implementation.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/advanced_assets/firebase_config.png b/docusaurus/docs/Flutter/assets/advanced_assets/firebase_config.png deleted file mode 100644 index d457638a7..000000000 Binary files a/docusaurus/docs/Flutter/assets/advanced_assets/firebase_config.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/advanced_assets/pip_example.png b/docusaurus/docs/Flutter/assets/advanced_assets/pip_example.png deleted file mode 100644 index 465fe3a8c..000000000 Binary files a/docusaurus/docs/Flutter/assets/advanced_assets/pip_example.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/advanced_assets/screen_sharing_dashboard.png b/docusaurus/docs/Flutter/assets/advanced_assets/screen_sharing_dashboard.png deleted file mode 100644 index c10b2f980..000000000 Binary files a/docusaurus/docs/Flutter/assets/advanced_assets/screen_sharing_dashboard.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/advanced_assets/screen_sharing_notification.png b/docusaurus/docs/Flutter/assets/advanced_assets/screen_sharing_notification.png deleted file mode 100644 index e0aca60c5..000000000 Binary files a/docusaurus/docs/Flutter/assets/advanced_assets/screen_sharing_notification.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/chat_with_video_call_screen.png b/docusaurus/docs/Flutter/assets/chat_with_video_call_screen.png deleted file mode 100644 index 99cfe7c85..000000000 Binary files a/docusaurus/docs/Flutter/assets/chat_with_video_call_screen.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/chat_with_video_channel_list.png b/docusaurus/docs/Flutter/assets/chat_with_video_channel_list.png deleted file mode 100644 index b6215b423..000000000 Binary files a/docusaurus/docs/Flutter/assets/chat_with_video_channel_list.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/chat_with_video_channel_screen.png b/docusaurus/docs/Flutter/assets/chat_with_video_channel_screen.png deleted file mode 100644 index 453248e19..000000000 Binary files a/docusaurus/docs/Flutter/assets/chat_with_video_channel_screen.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/chat_with_video_final_result.png b/docusaurus/docs/Flutter/assets/chat_with_video_final_result.png deleted file mode 100644 index 52e839c92..000000000 Binary files a/docusaurus/docs/Flutter/assets/chat_with_video_final_result.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/chat_with_video_home_screen.png b/docusaurus/docs/Flutter/assets/chat_with_video_home_screen.png deleted file mode 100644 index e4188fbfb..000000000 Binary files a/docusaurus/docs/Flutter/assets/chat_with_video_home_screen.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/chat_with_video_login_screen.png b/docusaurus/docs/Flutter/assets/chat_with_video_login_screen.png deleted file mode 100644 index 6d0132694..000000000 Binary files a/docusaurus/docs/Flutter/assets/chat_with_video_login_screen.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/add_reaction_option.png b/docusaurus/docs/Flutter/assets/cookbook/add_reaction_option.png deleted file mode 100644 index 42ea2da97..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/add_reaction_option.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/audio-volume-indicator.png b/docusaurus/docs/Flutter/assets/cookbook/audio-volume-indicator.png deleted file mode 100644 index 812431679..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/audio-volume-indicator.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/connection-unstable.png b/docusaurus/docs/Flutter/assets/cookbook/connection-unstable.png deleted file mode 100644 index 4b141e1bb..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/connection-unstable.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/custom-video-layout.png b/docusaurus/docs/Flutter/assets/cookbook/custom-video-layout.png deleted file mode 100644 index 4177b379c..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/custom-video-layout.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/feedback_dialog.png b/docusaurus/docs/Flutter/assets/cookbook/feedback_dialog.png deleted file mode 100644 index 71d3a038c..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/feedback_dialog.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/incoming-call.png b/docusaurus/docs/Flutter/assets/cookbook/incoming-call.png deleted file mode 100644 index 6c51a3cf7..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/incoming-call.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/livestreaming-dashboard.png b/docusaurus/docs/Flutter/assets/cookbook/livestreaming-dashboard.png deleted file mode 100644 index 6b51caa9c..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/livestreaming-dashboard.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/lobby-preview.png b/docusaurus/docs/Flutter/assets/cookbook/lobby-preview.png deleted file mode 100644 index b33e28908..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/lobby-preview.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/lobby_screen.png b/docusaurus/docs/Flutter/assets/cookbook/lobby_screen.png deleted file mode 100644 index 8ec3263fb..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/lobby_screen.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/network-quality.png b/docusaurus/docs/Flutter/assets/cookbook/network-quality.png deleted file mode 100644 index e4ae86f16..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/network-quality.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/no-video-fallback-avatar.png b/docusaurus/docs/Flutter/assets/cookbook/no-video-fallback-avatar.png deleted file mode 100644 index e4168bb9b..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/no-video-fallback-avatar.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/participant_label.png b/docusaurus/docs/Flutter/assets/cookbook/participant_label.png deleted file mode 100644 index 591dd2557..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/participant_label.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/permission-requests.png b/docusaurus/docs/Flutter/assets/cookbook/permission-requests.png deleted file mode 100644 index ffd2b323a..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/permission-requests.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/reaction_user.png b/docusaurus/docs/Flutter/assets/cookbook/reaction_user.png deleted file mode 100644 index f89bfa504..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/reaction_user.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/removing-label-and-indicators.png b/docusaurus/docs/Flutter/assets/cookbook/removing-label-and-indicators.png deleted file mode 100644 index dbcd403fb..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/removing-label-and-indicators.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/replacing-call-controls.png b/docusaurus/docs/Flutter/assets/cookbook/replacing-call-controls.png deleted file mode 100644 index 8ec1192de..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/replacing-call-controls.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/speaking-while-muted.png b/docusaurus/docs/Flutter/assets/cookbook/speaking-while-muted.png deleted file mode 100644 index ec4058898..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/speaking-while-muted.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/user-avatar.png b/docusaurus/docs/Flutter/assets/cookbook/user-avatar.png deleted file mode 100644 index ebf41f774..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/user-avatar.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/cookbook/video_fallback.png b/docusaurus/docs/Flutter/assets/cookbook/video_fallback.png deleted file mode 100644 index 74733ebc9..000000000 Binary files a/docusaurus/docs/Flutter/assets/cookbook/video_fallback.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/core_concepts/advanced-settings.png b/docusaurus/docs/Flutter/assets/core_concepts/advanced-settings.png deleted file mode 100644 index 79b56fc8e..000000000 Binary files a/docusaurus/docs/Flutter/assets/core_concepts/advanced-settings.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/core_concepts/call_member-grant-joincall.png b/docusaurus/docs/Flutter/assets/core_concepts/call_member-grant-joincall.png deleted file mode 100644 index d950f9b30..000000000 Binary files a/docusaurus/docs/Flutter/assets/core_concepts/call_member-grant-joincall.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/core_concepts/stats_screen.jpeg b/docusaurus/docs/Flutter/assets/core_concepts/stats_screen.jpeg deleted file mode 100644 index 747759613..000000000 Binary files a/docusaurus/docs/Flutter/assets/core_concepts/stats_screen.jpeg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/core_concepts/user-revoke-joincall.png b/docusaurus/docs/Flutter/assets/core_concepts/user-revoke-joincall.png deleted file mode 100644 index 1aee4570d..000000000 Binary files a/docusaurus/docs/Flutter/assets/core_concepts/user-revoke-joincall.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/installation/ios_permission.png b/docusaurus/docs/Flutter/assets/installation/ios_permission.png deleted file mode 100644 index ece596363..000000000 Binary files a/docusaurus/docs/Flutter/assets/installation/ios_permission.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/quick_start_assets/call_control_area.png b/docusaurus/docs/Flutter/assets/quick_start_assets/call_control_area.png deleted file mode 100644 index 4926a7537..000000000 Binary files a/docusaurus/docs/Flutter/assets/quick_start_assets/call_control_area.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/quick_start_assets/completed_app.png b/docusaurus/docs/Flutter/assets/quick_start_assets/completed_app.png deleted file mode 100644 index cd46dcf76..000000000 Binary files a/docusaurus/docs/Flutter/assets/quick_start_assets/completed_app.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/quick_start_assets/display_banner.png b/docusaurus/docs/Flutter/assets/quick_start_assets/display_banner.png deleted file mode 100644 index f15f146b9..000000000 Binary files a/docusaurus/docs/Flutter/assets/quick_start_assets/display_banner.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/quick_start_assets/modified_ui.png b/docusaurus/docs/Flutter/assets/quick_start_assets/modified_ui.png deleted file mode 100644 index 5245e0f7c..000000000 Binary files a/docusaurus/docs/Flutter/assets/quick_start_assets/modified_ui.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/tutorials/audio_room.png b/docusaurus/docs/Flutter/assets/tutorials/audio_room.png deleted file mode 100644 index de5f3ea03..000000000 Binary files a/docusaurus/docs/Flutter/assets/tutorials/audio_room.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/tutorials/livestreaming/obs_streaming.png b/docusaurus/docs/Flutter/assets/tutorials/livestreaming/obs_streaming.png deleted file mode 100644 index b4ad152e1..000000000 Binary files a/docusaurus/docs/Flutter/assets/tutorials/livestreaming/obs_streaming.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/tutorials/livestreaming/webrtc_streaming.png b/docusaurus/docs/Flutter/assets/tutorials/livestreaming/webrtc_streaming.png deleted file mode 100644 index d37636c9c..000000000 Binary files a/docusaurus/docs/Flutter/assets/tutorials/livestreaming/webrtc_streaming.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/tutorials/vc-create-flutter-project.png b/docusaurus/docs/Flutter/assets/tutorials/vc-create-flutter-project.png deleted file mode 100644 index 13fca9334..000000000 Binary files a/docusaurus/docs/Flutter/assets/tutorials/vc-create-flutter-project.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/tutorials/vc-create-project.png b/docusaurus/docs/Flutter/assets/tutorials/vc-create-project.png deleted file mode 100644 index 68aade96c..000000000 Binary files a/docusaurus/docs/Flutter/assets/tutorials/vc-create-project.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/tutorials/vc-key.png b/docusaurus/docs/Flutter/assets/tutorials/vc-key.png deleted file mode 100644 index 677cb36cf..000000000 Binary files a/docusaurus/docs/Flutter/assets/tutorials/vc-key.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/tutorials/vc-ui-1.png b/docusaurus/docs/Flutter/assets/tutorials/vc-ui-1.png deleted file mode 100644 index 14c77d95a..000000000 Binary files a/docusaurus/docs/Flutter/assets/tutorials/vc-ui-1.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/tutorials/vc-ui-2.png b/docusaurus/docs/Flutter/assets/tutorials/vc-ui-2.png deleted file mode 100644 index f489a646a..000000000 Binary files a/docusaurus/docs/Flutter/assets/tutorials/vc-ui-2.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/ui_component_assets/incoming_call_screen.png b/docusaurus/docs/Flutter/assets/ui_component_assets/incoming_call_screen.png deleted file mode 100644 index 0b177c5fe..000000000 Binary files a/docusaurus/docs/Flutter/assets/ui_component_assets/incoming_call_screen.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/ui_cookbook_participant_list_dominant_speaker.png b/docusaurus/docs/Flutter/assets/ui_cookbook_participant_list_dominant_speaker.png deleted file mode 100644 index 96703dc13..000000000 Binary files a/docusaurus/docs/Flutter/assets/ui_cookbook_participant_list_dominant_speaker.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/ui_cookbook_participant_list_final_result.png b/docusaurus/docs/Flutter/assets/ui_cookbook_participant_list_final_result.png deleted file mode 100644 index 81879e86d..000000000 Binary files a/docusaurus/docs/Flutter/assets/ui_cookbook_participant_list_final_result.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/ui_cookbook_participant_list_mute_icon.png b/docusaurus/docs/Flutter/assets/ui_cookbook_participant_list_mute_icon.png deleted file mode 100644 index 92aa18c6f..000000000 Binary files a/docusaurus/docs/Flutter/assets/ui_cookbook_participant_list_mute_icon.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/ui_cookbook_participant_list_without_muting.png b/docusaurus/docs/Flutter/assets/ui_cookbook_participant_list_without_muting.png deleted file mode 100644 index c0625ac87..000000000 Binary files a/docusaurus/docs/Flutter/assets/ui_cookbook_participant_list_without_muting.png and /dev/null differ diff --git a/docusaurus/sidebars-flutter.js b/docusaurus/sidebars-flutter.js deleted file mode 100644 index 5565574a3..000000000 --- a/docusaurus/sidebars-flutter.js +++ /dev/null @@ -1,54 +0,0 @@ -module.exports = { - mySidebar: [ - { - type: "category", - label: "Setup", - items: [ - { - type: "autogenerated", - dirName: "01-setup", - }, - ], - }, - { - type: "category", - label: "Core Concepts", - items: [ - { - type: "autogenerated", - dirName: "03-core-concepts", - }, - ], - }, - { - type: "category", - label: "UI Components", - items: [ - { - type: "autogenerated", - dirName: "04-ui", - }, - ], - }, - { - type: "category", - label: "UI Cookbook", - items: [ - { - type: "autogenerated", - dirName: "06-ui-cookbook", - }, - ], - }, - { - type: "category", - label: "Advanced Guides", - items: [ - { - type: "autogenerated", - dirName: "05-advanced", - }, - ], - }, - ], -};