diff --git a/.github/workflows/docusaurus.yml b/.github/workflows/docusaurus.yml deleted file mode 100644 index 815f82b654..0000000000 --- a/.github/workflows/docusaurus.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: docusaurus - -on: - push: - tags: - - '*.*.*' - - 'v*.*.*' - branches: - - master - paths: - - docusaurus/** -jobs: - push_docusaurus: - name: Publish docusaurus docs - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Setup Node 16 - uses: actions/setup-node@v4 - with: - node-version: 16 - - name: push - uses: GetStream/push-stream-chat-docusaurus-action@main - with: - target-branch: ${{ github.ref == 'refs/heads/master' && 'production' || 'staging' }} - 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 ad33a54afe..0000000000 --- a/.github/workflows/vale-doc-lint.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Check Docusaurus docs with vale linter - -on: [pull_request] - -jobs: - vale: - name: Vale doc linter - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: errata-ai/vale-action@v2.1.0 - with: - version: 3.0.3 - # added, diff_context, file, nofilter - # Default is added: results are filtered for added/modified files. Set to no filter when all files need to be checked. - # More info: https://github.com/errata-ai/vale-action and https://github.com/reviewdog/reviewdog#filter-mode - filter_mode: nofilter - # github-pr-check, github-pr-review, github-check - reporter: github-pr-check - # Set fail_on_error to true to make sure builds fail. - fail_on_error: true - files: '["docusaurus", "README.md"]' - env: - # Required, set by GitHub actions automatically: - # https://docs.github.com/en/actions/security-guides/automatic-token-authentication#about-the-github_token-secret - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.styles/Google/AMPM.yml b/.styles/Google/AMPM.yml deleted file mode 100644 index fbdc6e4f84..0000000000 --- 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 f41af0189b..0000000000 --- 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 99363fbd46..0000000000 --- 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 95234987be..0000000000 --- a/.styles/Google/Contractions.yml +++ /dev/null @@ -1,30 +0,0 @@ -extends: substitution -message: "Feel free to 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 e9d227fa13..0000000000 --- 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 1e070517bf..0000000000 --- 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 1befe72aa8..0000000000 --- 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 b314dc4e98..0000000000 --- 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 3e15181b2f..0000000000 --- a/.styles/Google/Exclamation.yml +++ /dev/null @@ -1,7 +0,0 @@ -extends: existence -message: "Don't use exclamation points in text." -link: 'https://developers.google.com/style/exclamation-points' -nonword: true -level: error -tokens: - - '\w!(?:\s|$)' diff --git a/.styles/Google/FirstPerson.yml b/.styles/Google/FirstPerson.yml deleted file mode 100644 index 0b7b8828ca..0000000000 --- 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 c8486181d6..0000000000 --- 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 261cfb666f..0000000000 --- a/.styles/Google/GenderBias.yml +++ /dev/null @@ -1,45 +0,0 @@ -extends: substitution -message: "Consider using '%s' instead of '%s'." -link: 'https://developers.google.com/style/inclusive-documentation' -ignorecase: true -level: error -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 b538be5b42..0000000000 --- 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 a53301338a..0000000000 --- a/.styles/Google/Headings.yml +++ /dev/null @@ -1,29 +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 - - Code - - 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 d91700de3f..0000000000 --- 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 ac8f557a4a..0000000000 --- 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 f858ea6fee..0000000000 --- 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 d1ac7d27e8..0000000000 --- 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 b9ba21ebb2..0000000000 --- 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 3b8711d0c8..0000000000 --- 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 3265890e52..0000000000 --- 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 d24a6a6c03..0000000000 --- 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 3cb6f1abd1..0000000000 --- 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 3ec045e777..0000000000 --- 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 bb8b85b420..0000000000 --- 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 63f4c248a8..0000000000 --- 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 27f7ca2bdc..0000000000 --- a/.styles/Google/Spacing.yml +++ /dev/null @@ -1,8 +0,0 @@ -extends: existence -message: "'%s' should have one space." -link: 'https://developers.google.com/style/sentence-spacing' -level: error -nonword: true -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 57acb88414..0000000000 --- a/.styles/Google/Spelling.yml +++ /dev/null @@ -1,8 +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?' - - '(?:\w+)logue' diff --git a/.styles/Google/Units.yml b/.styles/Google/Units.yml deleted file mode 100644 index 379fad6b8e..0000000000 --- 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: - - \d+(?:B|kB|MB|GB|TB) - - \d+(?:ns|ms|s|min|h|d) diff --git a/.styles/Google/Will.yml b/.styles/Google/Will.yml deleted file mode 100644 index 128a918362..0000000000 --- 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 bb711517e6..0000000000 --- a/.styles/Google/WordList.yml +++ /dev/null @@ -1,80 +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 - 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 diff --git a/.styles/Google/meta.json b/.styles/Google/meta.json deleted file mode 100644 index a5da2a8480..0000000000 --- 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 e69de29bb2..0000000000 diff --git a/.styles/config/vocabularies/Base/accept.txt b/.styles/config/vocabularies/Base/accept.txt deleted file mode 100644 index bc7aba922f..0000000000 --- a/.styles/config/vocabularies/Base/accept.txt +++ /dev/null @@ -1,15 +0,0 @@ -API -SDK -Crashlytics -Rollbar -APIs -boolean -Giphy -DM -UI -[Ss]lidable -discoverability -[Ll]ivestream -monorepo -Melos -uploader \ 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 e69de29bb2..0000000000 diff --git a/.vale.ini b/.vale.ini deleted file mode 100644 index f295edcae9..0000000000 --- a/.vale.ini +++ /dev/null @@ -1,17 +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/docusaurus/docs/Flutter/01-basics/installation.mdx b/docusaurus/docs/Flutter/01-basics/installation.mdx deleted file mode 100644 index 43972c8625..0000000000 --- a/docusaurus/docs/Flutter/01-basics/installation.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: installation -title: Installation ---- - -Choosing The Right Flutter Package - -### Why the SDK is split into different packages - -Different applications need different levels of customization and integration with the Stream Chat SDK. -To do this, the Flutter SDK is split into three different packages which build upon the last and give -varying levels of control to the developer. The higher level packages offer better compatibility out of the -box while the lower level SDKs offer fine grained control. There is also a separate package for persistence -which allows you persist data locally which works with all packages. - -### How do I choose? - -#### The case for `stream_chat_flutter` - -For the quickest way to integrate Stream Chat with your app, the UI SDK (`stream_chat_flutter`) is the -way to go. `stream_chat_flutter` contains prebuilt components that manage most operations like data -fetching, pagination, sending a message, and more. This ensures you have a nearly out-of-the-box -experience adding chat to your applications. It is also possible to use this in conjunction with -lower level operations of the SDK to get the best of both worlds. - -:::note -The package allows customization of components to a large extent making it easy to tweak the theme -to match your app colors and such. If you require any additional feature or customization, feel free -to request this through our support channels. -::: - -Summary: - -For the quickest and easiest way to add Chat to your app with prebuilt UI components, use `stream_chat_flutter` - - -#### The case for `stream_chat_flutter_core` - -If your application involves UI that does not fit in with the `stream_chat_flutter` components, `stream_chat_flutter_core` -strips away the UI associated with the components and provides the data fetching and manipulation -capabilities while supplying builders for UI. This allows you to implement your own UI and themes -completely independently while not worrying about writing functions for data and pagination. - -Summary: - -For implementing your own custom UI while not having to worry about lower level API calls, use `stream_chat_flutter_core`. - -#### The case for `stream_chat` - -The `stream_chat` package is the Low-level Client (LLC) of Stream Chat in Flutter. This package wraps -the underlying functionality of Stream Chat and allows the most customization in terms of UI, data, -and architecture. - -Summary: - -For the most control over the SDK and dealing with low level calls to the API, use `stream_chat`. - -### Versioning Policy - -All of the Stream Chat packages follow [semantic versioning](https://semver.org/). - -That means that with a version number x.y.z (major.minor.patch): -- When releasing bug fixes (backwards compatible), we make a patch release by changing the z number (ex: 3.6.2 to 3.6.3). A bug fix is defined as an internal change that fixes incorrect behavior. -- When releasing new features or non-critical fixes, we make a minor release by changing the y number (ex: 3.6.2 to 3.7.0). -- When releasing breaking changes (backward incompatible), we make a major release by changing the x number (ex: 3.6.2 to 4.0.0). - -See the [semantic versioning](https://dart.dev/tools/pub/versioning#semantic-versions) section from the Dart docs for more information. - -This versioning policy does not apply to prerelease packages (below major version of 1). See this -[StackOverflow thread](https://stackoverflow.com/questions/66201337/how-do-dart-package-versions-work-how-should-i-version-my-flutter-plugins) -for more information on Dart package versioning. - -Whenever possible, we will add deprecation warnings in preparation for future breaking changes. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/01-basics/introduction.mdx b/docusaurus/docs/Flutter/01-basics/introduction.mdx deleted file mode 100644 index a618bbeb21..0000000000 --- a/docusaurus/docs/Flutter/01-basics/introduction.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -slug: / -id: introduction -title: Overview ---- -About The Flutter SDK - -![](../assets/sdk_title.png) - -Stream Chat is a service that helps you easily build a full chat experience in your Flutter apps. -We also support a variety of other SDKs. - -This section of the documentation focuses on our Flutter SDK which helps you easily -ship high quality messaging experiences in apps and programs built with the [Flutter toolkit -made by Google](https://flutter.dev). - -The Stream Chat Flutter SDK comprises five different packages to choose from, ranging from ones -giving you complete control to ones that give you a rich out-of-the-box chat experience. - -The packages that make up the Stream Chat SDK are: - -1. Low Level Client (`stream_chat`): a pure Dart package that can be used on any Dart project. -It provides a low-level client to access the Stream Chat service. -2. Core (`stream_chat_flutter_core`): provides business logic to fetch common things required -for integrating Stream Chat into your application. -The core package allows more customisation and hence provides business logic but no UI components. -3. UI (`stream_chat_flutter`): this library includes both a low-level chat SDK and a set of -reusable and customizable UI components. -4. Persistence (`stream_chat_persistence`): provides a persistence client for fetching and -saving chat data locally. -5. Localizations (`stream_chat_localizations`): provides a set of localizations for the SDK. - -We recommend building prototypes using the full UI package, [`stream_chat_flutter`](https://pub.dev/packages/stream_chat_flutter), -since it contains UI widgets already integrated with Stream's API. It is the fastest way to get up -and running using Stream chat in your app. - -The Flutter SDK enables you to build any type of chat or messaging experience for Android, iOS, Web -and Desktop. - -If you're building a very custom UI and would prefer a more lean package, -[`stream_chat_flutter_core`](https://pub.dev/packages/stream_chat_flutter_core) will be suited to this -use case. Core allows you to build custom, expressive UIs while retaining the benefits of our full -Flutter SDK. APIs for accessing and controlling users, sending messages, and so forth are seamlessly integrated -into this package and accessible via providers and builders. - -Before going into the docs, let's take a small detour to look at how the elements of Stream Chat are structured. - -### Basic Structure - -There are two core elements in chat, Users and Channels. -Channels are groups of one or more users that can message each other. -In an app, you need to have a user connected to query channels. - -There is no specific distinction between a chat with only two people and a group chat, -but there is a way to create a unique chat between a certain number of people by creating a distinct channel. - -![](../assets/chat_basics.png) - -In essence, a normal two-person chat would be a distinct channel created with two members (you cannot add or delete members in this channel), whereas a group created with two people would simply be a non distinct channel (possible to add or remove members). - -:::note -It is also possible to add more than two people in a distinct channel which retains the same add/removal properties and resembles the Slack DMs where you can DM one or more people as well. -::: - -In summary, if you were creating a Whatsapp-like app, the first screen would be a list of channels - which on opening would show a list of messages that were sent by the users in the Channel. - -While this is a simplistic overview of the service, the Flutter SDK handles the UI and more time consuming things (media upload, offline storage, theming, etc.) for you. - -Before reading the docs, consider trying our [online API tour](https://getstream.io/chat/get_started/), -it is a nice way to learn how the API works. -It's in-browser so you'll need to use JavaScript but the core concepts are pretty much the same as Dart. - -You may also like to look at the [Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) -which focuses on using the UI package to get Stream Chat integrated into a Flutter app. - -Further sections break down each individual packages and explain several common operations. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/01-customize_message_widget.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/01-customize_message_widget.mdx deleted file mode 100644 index f6d524d96d..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/01-customize_message_widget.mdx +++ /dev/null @@ -1,229 +0,0 @@ ---- -id: customize_message_widget -title: Message ---- - -Customizing Text Messages with the StreamMessageWidget - -### Introduction - -Every application provides a unique look and feel to their own messaging interface including and not -limited to fonts, colors, and shapes. - -This guide details how to customize the `StreamMessageWidget` in the Stream Chat Flutter UI SDK. - -### Building Custom Messages - -This guide goes into detail about the ability to customize the `StreamMessageWidget`. However, if you want -to customize the default `StreamMessageWidget` in the `StreamMessageListView` provided, you can use the `.copyWith()` method -provided inside the `messageBuilder` parameter of the `StreamMessageListView` like this: - -```dart -StreamMessageListView( - messageBuilder: (context, details, messageList, defaultImpl) { - return defaultImpl.copyWith( - ... - ); - }, -), -``` - -### Providing Custom Reaction Icons - -By default the `StreamReactionIcon` widgets provided by the SDK are `love`, `like`, `sad`, `haha`, and `wow`. -However, you can provide your own custom reaction icons by providing a `reactionIcons` parameter to the `StreamChatConfigurationData`. - -```dart -StreamChat( - client: client, - streamChatConfigData: StreamChatConfigurationData( - reactionIcons: [ - StreamReactionIcon( - type: 'custom', - builder: (context, isHighlighted, iconSize) { - return Icon( - Icons.star, - size: iconSize, - color: isHighlighted ? Colors.red : Colors.black, - ); - }, - ), - ] - ), - child: //Your widget here -) -``` - -### Theming - -You can customize the `StreamMessageWidget` using the `StreamChatTheme` class, so that you can change the -message theme at the top instead of creating your own `StreamMessageWidget` at the lower implementation level. - -There are several things you can change in the theme including text styles and colors of various elements. - -You can also set a different theme for the user's own messages and messages received by them. - -:::note -Theming allows you to change minor factors like style while using the widget directly allows you much -more customization such as replacing a certain widget with another. Some things can only be customized -through the widget and not the theme. -::: - -Here is an example: - -```dart -StreamChatThemeData( - - /// Sets theme for user's messages - ownMessageTheme: StreamMessageThemeData( - messageBackgroundColor: colorTheme.textHighEmphasis, - ), - - /// Sets theme for received messages - otherMessageTheme: StreamMessageThemeData( - avatarTheme: StreamAvatarThemeData( - borderRadius: BorderRadius.circular(8), - ), - ), - -) -``` - -![](../../assets/message_theming.png) - -#### Change message text style - -The `StreamMessageWidget` has multiple `Text` widgets that you can manipulate the styles of. The three main -are the actual message text, user name, message links, and the message timestamp. - -```dart -StreamMessageThemeData( - messageTextStyle: TextStyle(...), - createdAtStyle: TextStyle(...), - messageAuthorStyle: TextStyle(...), - messageLinksStyle: TextStyle(...), -) -``` - -![](../../assets/message_styles.png) - -#### Change avatar theme - -You can change the attributes of the avatar (if displayed) using the `avatarTheme` property. - -```dart -StreamMessageThemeData( - avatarTheme: StreamAvatarThemeData( - borderRadius: BorderRadius.circular(8), - ), -) -``` - -![](../../assets/message_rounded_avatar.png) - -#### Changing Reaction theme - -You also customize the reactions attached to every message using the theme. - -```dart -StreamMessageThemeData( - reactionsBackgroundColor: Colors.red, - reactionsBorderColor: Colors.redAccent, - reactionsMaskColor: Colors.pink, -), -``` - -![](../../assets/message_reaction_theming.png) - -### Changing Message Actions - -When a message is long pressed, the `StreamMessageActionsModal` is shown. - -The `StreamMessageWidget` allows showing or hiding some options if you so choose. - -```dart -StreamMessageWidget( - ... - showUsername = true, - showTimestamp = true, - showReactions = true, - showDeleteMessage = true, - showEditMessage = true, - showReplyMessage = true, - showThreadReplyMessage = true, - showResendMessage = true, - showCopyMessage = true, - showFlagButton = true, - showPinButton = true, - showPinHighlight = true, -), -``` - -![](../../assets/message_widget_actions.png) - -### Building attachments - -The `attachmentBuilders` property allows you to build any kind of attachment (inbuilt or custom) -in your own way. While a separate guide is written for this, it is included here because of relevance. - -```dart -class LocationAttachmentBuilder extends StreamAttachmentWidgetBuilder { - @override - bool canHandle( - Message message, - Map> attachments, - ) { - final imageAttachments = attachments['location']; - return imageAttachments != null && imageAttachments.length == 1; - } - - @override - Widget build( - BuildContext context, - Message message, - Map> attachments, - ) { - final attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'], - attachments[0].extraData['longitude'], - ), - ); - - return WrapAttachmentWidget( - attachmentWidget: attachmentWidget, - attachmentShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - ); - } -} - -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - attachmentBuilders: const [ - LocationAttachmentBuilder(), - ], - ); - }, -), -``` - -### Widget Builders - -Some parameters allow you to construct your own widget in place of some elements in the `StreamMessageWidget`. - -These are: -* `userAvatarBuilder` : Allows user to substitute their own widget in place of the user avatar. -* `editMessageInputBuilder` : Allows user to substitute their own widget in place of the input in edit mode. -* `textBuilder` : Allows user to substitute their own widget in place of the text. -* `bottomRowBuilder` : Allows user to substitute their own widget in the bottom of the message when not deleted. -* `deletedBottomRowBuilder` : Allows user to substitute their own widget in the bottom of the message when deleted. - -```dart -StreamMessageWidget( - ... - textBuilder: (context, message) { - // Add your own text implementation here. - }, -), -``` diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/02-customize_text_messages.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/02-customize_text_messages.mdx deleted file mode 100644 index da6071843f..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/02-customize_text_messages.mdx +++ /dev/null @@ -1,162 +0,0 @@ ---- -id: customize_text_messages -title: Message List View ---- - -Customizing Text Messages - -### Introduction - -Every application provides a unique look and feel to their own messaging interface including and not -limited to fonts, colors, and shapes. - -This guide details how to customize message text in the `StreamMessageListView` / `StreamMessageWidget` in the -Stream Chat Flutter UI SDK. - -:::note -This guide is specifically for the `StreamMessageListView` but if you intend to display a `StreamMessageWidget` -separately, follow the same process without the `.copyWith` and use the default constructor instead. -::: - -### Basics of customizing a `StreamMessageWidget` - -First, add a `StreamMessageListView` in the appropriate place where you intend to display messages from a -channel. - -```dart -StreamMessageListView( - ... -) -``` - -Now, we use the `messageBuilder` parameter to build a custom message. The builder function also provides -the default implementation of the `StreamMessageWidget` so that we can change certain aspects of the widget -without redoing all of the default parameters. - -:::note -In earlier versions of the SDK, some `StreamMessageWidget` parameters were exposed directly through the `StreamMessageListView`, -however, this quickly becomes hard to maintain as more parameters and customizations are added to the -`StreamMessageWidget`. Newer version utilise a cleaner interface to change the parameters by supplying a -default message implementation as aforementioned. -::: - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget; - }, -) -``` - -We use `.copyWith()` to customize the widget: - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - ... - ); - }, -) -``` - -### Customizing text - -If you intend to simply change the theme for the text, you need not recreate the whole widget. The -`StreamMessageWidget` has a `messageTheme` parameter that allows you to pass the theme for most aspects -of the message. - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - messageTheme: StreamMessageThemeData( - ... - messageTextStyle: TextStyle(), - ), - ); - }, -) -``` - -If you want to replace the entire text widget in the `StreamMessageWidget`, you can use the `textBuilder` -parameter which provides a builder for creating a widget to substitute the default text.parameter - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - textBuilder: (context, message) { - return Text(message.text ?? ''); - }, - ); - }, -) -``` - -### Adding Hashtags - -To add elements like hashtags, we can override the `textBuilder` in the StreamMessageWidget: - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - textBuilder: (context, message) { - final text = _replaceHashtags(message.text)?.replaceAll('\n', '\\\n'); - final messageTheme = StreamChatTheme.of(context).ownMessageTheme; - - if (text == null) return const SizedBox(); - - return MarkdownBody( - data: text, - onTapLink: ( - String link, - String? href, - String title, - ) { - // Do something with tapped hashtag - }, - styleSheet: MarkdownStyleSheet.fromTheme( - Theme.of(context).copyWith( - textTheme: Theme.of(context).textTheme.apply( - bodyColor: messageTheme.messageTextStyle?.color, - decoration: messageTheme.messageTextStyle?.decoration, - decorationColor: messageTheme.messageTextStyle?.decorationColor, - decorationStyle: messageTheme.messageTextStyle?.decorationStyle, - fontFamily: messageTheme.messageTextStyle?.fontFamily, - ), - ), - ).copyWith( - a: messageTheme.messageLinksStyle, - p: messageTheme.messageTextStyle, - ), - ); - }, - ); - }, -) - -String? _replaceHashtags(String? text) { - if (text == null) return null; - - final exp = RegExp(r"\B#\w\w+"); - String result = text; - exp.allMatches(text).forEach((match){ - text = text!.replaceAll( - '${match.group(0)}', '[${match.group(0)}](${match.group(0)?.replaceAll(' ', '')})'); - }); - return result; -} -``` - -We can replace the hashtags using RegEx and add links for the MarkdownBody which is done here in the -`_replaceHashtags()` function. -Inside the textBuilder, we use the `flutter_markdown` package to build our hashtags as links. - -![](../../assets/hashtag_example.jpg) diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/03-customize_message_actions.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/03-customize_message_actions.mdx deleted file mode 100644 index 865cccb701..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/03-customize_message_actions.mdx +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: customize_message_actions -title: Message Actions ---- - -Customizing Message Actions - -### Introduction - -Message actions pop up in message overlay, when you long-press a message. - -![](../../assets/message_actions.jpg) - -We have provided granular control over these actions. - -By default we render the following message actions: - -* edit message - -* delete message - -* reply - -* thread reply - -* copy message - -* flag message - -* pin message - -* mark unread - -:::note -Edit and delete message are only available on messages sent by the user. -Additionally, pinning a message requires you to add the roles which are allowed to pin messages. -::: - -:::note -Mark unread message is only available on messages sent by other users and only when read events are enabled for the channel. -Additionally, it's not possible to mark messages inside threads as unread. -::: - -### Partially remove some message actions - -For example, if you only want to keep "copy message" and "delete message": -here is how to do it using the `messageBuilder` with our `StreamMessageWidget`. - -```dart -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - showFlagButton: false, - showEditMessage: false, - showCopyMessage: true, - showDeleteMessage: details.isMyMessage, - showReplyMessage: false, - showThreadReplyMessage: false, - showMarkUnreadMessage: false, - ); - }, -) -``` - -### Add a new custom message action - -The SDK also allows you to add new actions into the dialog. - -For example, let's suppose you want to introduce a new message action - "Demo Action": - -We use the `customActions` parameter of the `StreamMessageWidget` to add extra actions. - -```dart -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - customActions: [ - StreamMessageAction( - leading: const Icon(Icons.add), - title: const Text('Demo Action'), - onTap: (message) { - /// Complete action here - }, - ), - ], - ); - }, -) -``` diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/04-adding_custom_attachments.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/04-adding_custom_attachments.mdx deleted file mode 100644 index 2954523b75..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/04-adding_custom_attachments.mdx +++ /dev/null @@ -1,269 +0,0 @@ ---- -id: adding_custom_attachments -title: Attachments ---- - -Adding Your Own Types Of Attachments To A Message - -### Introduction - -Stream Chat supports attachment types like images, video and files by default. You can also add your -own types of attachments through the SDK such as location, audio, etc. - -This involves doing three things: - -1) Rendering the attachment thumbnail in the `StreamMessageInput` - -2) Sending a message with the custom attachment - -3) Rendering the custom message attachment - -To do this, let's check out an example to add location sharing to Stream Chat. - -### Location Sharing - -Let's build an example of location sharing option in the app: - -![](../../assets/location_sharing_example.jpg) - -* Show a "Share Location" button next to StreamMessageInput `Textfield`. - -* When the user presses this button, it should fetch the current location coordinates of the user, and send a message on the channel as follows: - -```dart -Message( - text: 'This is my location', - attachments: [ - Attachment( - uploadState: const UploadState.success(), - type: 'location', - extraData: const { - 'latitude': 'fetched_latitude', - 'longitude': 'fetched_longitude', - }, - ), - ], -) -``` - -For our example, we are going to use [`geolocator`](https://pub.dev/packages/geolocator) library. -Please check their [setup instructions](https://pub.dev/packages/geolocator) on their docs. - -NOTE: If you are testing on iOS simulator, you will need to set some dummy coordinates, as mentioned [here](https://stackoverflow.com/a/31238119/7489541). -Also don't forget to enable "location update" capability in background mode, from XCode. - -On the receiver end, `location` type attachment should be rendered in map view, in the `StreamMessageListView`. -We are going to use [Google Static Maps API](https://developers.google.com/maps/documentation/maps-static/overview) to render the map in the message. -You can use other libraries as well such as [`google_maps_flutter`](https://pub.dev/packages/google_maps_flutter). - -First, we add a button which when clicked fetches and shares location into the `MessageInput`: - -```dart -StreamMessageInput( - actions: [ - InkWell( - child: const Icon( - Icons.location_on, - size: 20, - color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, - ), - onTap: () { - final channel = StreamChannel.of(context).channel; - - _determinePosition().then((value) { - channel.sendMessage( - Message( - text: 'This is my location', - attachments: [ - Attachment( - uploadState: const UploadState.success(), - type: 'location', - extraData: { - 'latitude': value.latitude.toString(), - 'longitude': value.longitude.toString(), - }, - ), - ], - ), - ); - }).catchError((err) { - print('Error getting location!'); - }); - }, - ), - ], -), - -Future _determinePosition() async { - bool serviceEnabled; - LocationPermission permission; - - serviceEnabled = await Geolocator.isLocationServiceEnabled(); - if (!serviceEnabled) { - return Future.error('Location services are disabled.'); - } - - permission = await Geolocator.checkPermission(); - if (permission == LocationPermission.denied) { - permission = await Geolocator.requestPermission(); - if (permission == LocationPermission.deniedForever) { - return Future.error( - 'Location permissions are permanently denied, we cannot request permissions.'); - } - - if (permission == LocationPermission.denied) { - return Future.error( - 'Location permissions are denied'); - } - } - - return await Geolocator.getCurrentPosition(); -} -``` - -Next, we build the Static Maps URL (Add your API key before using the code snippet): - -```dart - String _buildMapAttachment(String lat, String long) { - final url = Uri( - scheme: 'https', - host: 'maps.googleapis.com', - port: 443, - path: '/maps/api/staticmap', - queryParameters: { - 'center': '${lat},${long}', - 'zoom': '15', - 'size': '600x300', - 'maptype': 'roadmap', - 'key': 'YOUR_API_KEY', - 'markers': 'color:red|${lat},${long}' - }); - - return url.toString(); - } -``` - -And then modify the `StreamMessageListView` and tell it how to build a location attachment, using the `messageBuilder` property and copying the default message implementation overriding the `customAttachmentBuilders` property: - -```dart -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - customAttachmentBuilders: { - 'location': (context, message, attachments) { - final attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'].toString(), - attachments[0].extraData['longitude'].toString(), - ), - ); - - return WrapAttachmentWidget( - attachmentWidget: attachmentWidget, - attachmentShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - ); - } - }, - ); - }, -), -``` - -This gives us the final location attachment: - -![](../../assets/location_sharing_example_message.jpg) - -Additionally, you can also add a thumbnail if a message has a location attachment (unlike in this case, where we sent the message directly). - -To do this, we will: - -1) Add an attachment instead of sending a message - -2) Customize the `StreamMessageInput` - -First, we add the attachment when the location button is clicked: - -```dart - StreamMessageInputController _messageInputController = StreamMessageInputController(); - - StreamMessageInput( - messageInputController: _messageInputController, - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20, - color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, - ), - onTap: () { - _determinePosition().then((value) { - _messageInputController.addAttachment( - Attachment( - uploadState: const UploadState.success(), - type: 'location', - extraData: { - 'latitude': value.latitude.toString(), - 'longitude': value.longitude.toString(), - }, - ), - ); - }).catchError((err) { - print('Error getting location!'); - }); - }, - ), - ], - ), -``` - -After this, we can build the thumbnail: - -```dart -StreamMessageInput( - messageInputController: _messageInputController, - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20, - color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, - ), - onTap: () { - _determinePosition().then((value) { - _messageInputController.addAttachment( - Attachment( - uploadState: const UploadState.success(), - type: 'location', - extraData: { - 'latitude': value.latitude.toString(), - 'longitude': value.longitude.toString(), - }, - ), - ); - }).catchError((err) { - print('Error getting location!'); - }); - }, - ), - ], - mediaAttachmentBuilder: ( - BuildContext context, - Attachment attachment, - ValueSetter? onRemovePressed, - ) { - if (attachment.type == 'location') { - return Image.network( - _buildMapAttachment( - attachment.extraData['latitude'].toString(), - attachment.extraData['longitude'].toString(), - ), - ); - } - return const SizedBox(); - }, -), -``` - -And we can see the thumbnails in the StreamMessageInput: - -![](../../assets/location_sharing_example_message_thumbnail.jpg) diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/05-customize_attachment_picker_modal.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/05-customize_attachment_picker_modal.mdx deleted file mode 100644 index db4cb97b10..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/05-customize_attachment_picker_modal.mdx +++ /dev/null @@ -1,167 +0,0 @@ ---- -id: customize_attachment_picker_modal -title: Attachment Picker Modal ---- - -Customizing the Attachment Picker Modal - -### Introduction - -The Attachment Picker is a modal that allows users to select attachments from their device. -It is generally used when a user taps the attachment button in the [StreamMessageInput](../07-message_composer/stream_message_input.mdx). - -By default, the Attachment Picker provides multiple picker options as per the platform. -- For example, on Mobile, the default options are Camera, Gallery, File, and Video. -- On Web and Desktop, the default options are Image, Video and File. - -### Customizing the Attachment Picker Modal - -The Attachment Picker Modal can be customized by passing the different values to the `showStreamAttachmentPickerModalBottomSheet` function. - -#### Initial Attachments - -The initial attachments can be passed to the Attachment Picker Modal in two ways. - - * By passing the `initialAttachments` parameter. - - ```dart - StreamMessageInputController _messageInputController = - StreamMessageInputController(); - ... - showStreamAttachmentPickerModalBottomSheet( - context: context, - initialAttachments: [ - // Pass the initial attachments to the modal here if any are available already (optional) - ..._messageInputController.attachments, - ], - ); - ``` - - * By creating a new instance of the `AttachmentPickerModalController` and passing it to the `controller` parameter. - - ```dart - final attachmentPickerController = StreamAttachmentPickerController( - initialAttachments: [ - // Pass the initial attachments to the modal here if any are available already (optional) - ...messageInputController.attachments, - ], - - // The `maxAttachmentSize` and `maxAttachmentCount` can also be set while creating a controller. - maxAttachmentSize: 10 * 1024 * 1024, // 10 MB - maxAttachmentCount: 10, // 10 attachments - ); - - showStreamAttachmentPickerModalBottomSheet( - context: context, - controller: attachmentPickerController, - ); - ``` - -#### Custom Attachment Picker Options - -The Attachment Picker Modal provides a default set of options as per the platform. -However, you can also customize the options by passing the `customOptions` parameter. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - customOptions: [ - // Pass the custom attachment picker options here - AttachmentPickerOption( - icon: const Icon(Icons.audiotrack), - supportedTypes: [AttachmentPickerType.audios], - optionViewBuilder: (context, attachmentPickerController) { - return AudioPicker( - onAudioPicked: (audio) async { - await attachmentPickerController.addAttachment(audio); - return Navigator.pop(context, attachmentPickerController.value); - }, - ); - }, - ), - ], - ); - ``` - -#### Attachment thumbnail size - -The size of the attachment thumbnail item shown in the gallery picker can be defined by passing the `attachmentThumbnailSize` parameter. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - attachmentThumbnailSize: const ThumbnailSize.square(600), - ); - ``` - -#### Attachment thumbnail format - -The format of the attachment thumbnail item shown in the gallery picker can be defined by passing the `attachmentThumbnailFormat` parameter. - -Possible values are `ThumbnailFormat.jpeg` and `ThumbnailFormat.png`. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - attachmentThumbnailFormat: ThumbnailFormat.jpeg, - ); - ``` - -#### Attachment thumbnail quality - -The quality of the attachment thumbnail item shown in the gallery picker can be defined by passing the `attachmentThumbnailQuality` parameter. - -Possible values are between 0 and 100. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - attachmentThumbnailQuality: 70, - ); - ``` - -#### Attachment thumbnail scale - -The scale of the attachment thumbnail item shown in the gallery picker can be defined by passing the `attachmentThumbnailScale` parameter. - -For example, if this is 2, it means that there are four image pixels for every one logical pixel, and the image's actual width and height are -double the height and width that should be used when painting the image. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - attachmentThumbnailScale: 2, - ); - ``` - -#### Additional modal bottom sheet parameters - -The `showStreamAttachmentPickerModalBottomSheet` function also accepts the parameters that are available in the `showModalBottomSheet` function. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - useRootNavigator: true, - elevation: 4, - isDismissible: true, - clipBehavior: Clip.antiAlias, - barrierColor: Colors.black.withOpacity(0.5), - constraints: const BoxConstraints( - maxHeight: 500, - maxWidth: 500, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(16), - ), - ), - ); - ``` - - - - - - diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/06-autocomplete_triggers.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/06-autocomplete_triggers.mdx deleted file mode 100644 index 0a3d9d309a..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/06-autocomplete_triggers.mdx +++ /dev/null @@ -1,118 +0,0 @@ ---- -id: autocomplete_triggers -title: Autocomplete Triggers ---- - -Adding Custom Autocomplete Triggers - -### Introduction - -The [StreamMessageInput](../07-message_composer/stream_message_input.mdx) widget provides a way to add custom autocomplete triggers using the `StreamMessageInput.customAutocompleteTriggers` property. - -By default we provide autocomplete triggers for mentions and commands, but it's very easy to add your custom ones. - -### Add Emoji Autocomplete Trigger - -To add a custom emoji autocomplete trigger, you must first create an `AutoCompleteOptions` widget. -This widget will be used to show the autocomplete options. - -For this example we're using two external dependencies: - -- [emojis](https://pub.dev/packages/emojis) -- [`substring_highlight`](https://pub.dev/packages/substring_highlight) - -```dart -import 'package:emojis/emoji.dart'; -import 'package:flutter/material.dart'; - -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:substring_highlight/substring_highlight.dart'; - -/// Overlay for displaying emoji that can be used -class StreamEmojiAutocompleteOptions extends StatelessWidget { - /// Constructor for creating a [StreamEmojiAutocompleteOptions] - const StreamEmojiAutocompleteOptions({ - super.key, - required this.query, - this.onEmojiSelected, - }); - - /// Query for searching emoji. - final String query; - - /// Callback called when an emoji is selected. - final ValueSetter? onEmojiSelected; - - @override - Widget build(BuildContext context) { - final emojis = Emoji.all().where((it) { - final normalizedQuery = query.toUpperCase(); - final normalizedShortName = it.shortName.toUpperCase(); - - return normalizedShortName.contains(normalizedQuery); - }); - - if (emojis.isEmpty) return const SizedBox.shrink(); - - return StreamAutocompleteOptions( - options: emojis, - optionBuilder: (context, emoji) { - final themeData = Theme.of(context); - return ListTile( - dense: true, - horizontalTitleGap: 0, - leading: Text( - emoji.char, - style: themeData.textTheme.titleLarge!.copyWith( - fontSize: 24, - ), - ), - title: SubstringHighlight( - text: emoji.shortName, - term: query, - textStyleHighlight: themeData.textTheme.titleLarge!.copyWith( - color: Colors.yellow, - fontSize: 14.5, - fontWeight: FontWeight.bold, - ), - textStyle: themeData.textTheme.titleLarge!.copyWith( - fontSize: 14.5, - ), - ), - onTap: onEmojiSelected == null ? null : () => onEmojiSelected!(emoji), - ); - }, - ); - } -} -``` - -Now it's time to use the `StreamEmojiAutocompleteOptions` widget. - -```dart -StreamMessageInput( - customAutocompleteTriggers: [ - StreamAutocompleteTrigger( - trigger: ':', - minimumRequiredCharacters: 2, - optionsViewBuilder: ( - context, - autocompleteQuery, - messageEditingController, - ) { - final query = autocompleteQuery.query; - return StreamEmojiAutocompleteOptions( - query: query, - onEmojiSelected: (emoji) { - // accepting the autocomplete option. - StreamAutocomplete.of(context).acceptAutocompleteOption( - emoji.char, - keepTrigger: false, - ); - }, - ); - }, - ), - ], -), -``` diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/07-slidable_channel_list_preview.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/07-slidable_channel_list_preview.mdx deleted file mode 100644 index 38bf429f6c..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/07-slidable_channel_list_preview.mdx +++ /dev/null @@ -1,212 +0,0 @@ ---- -id: slidable_channel_list_preview -title: Channel List Preview ---- - -Slidable Channel List Preview - -### Introduction - -The default slidable behavior within the channel list has been removed in v4 of the Stream Chat Flutter SDK. -This guide will show you how you can easily add this functionality yourself. - -Please see our [full v4 migration guide](../../05-guides/08-migrations/migration_guide_4_0.mdx) if you're migrating from an earlier version of the Stream Chat Flutter SDK. - -![Slidable demo](../../assets/slidable_demo.jpg) - -### Prerequisites - -This guide assumes you are familiar with the Stream Chat SDK. -If you're new to Stream Chat Flutter, we recommend looking at our [getting started tutorial](https://getstream.io/chat/flutter/tutorial/). - -**Dependencies:** - -```dart -dependencies: - flutter: - sdk: flutter - stream_chat_flutter: ^6.0.0 - flutter_slidable: ^3.0.0 -``` - -⚠️ Note: The examples shown in this guide use the above packages and versions. - -### Example Code - Custom Stream Channel Item Builder - -In this example, you are doing a few important things in the ChannelListPage widget. You're: - -- Using the **flutter_slidable** package to easily add slide functionality. -- Passing in the `itemBuilder` argument for the **StreamChannelListView** widget. This gives access to the current **BuildContext**, **Channel**, and **StreamChannelListTile**, and allows you to create, or customize, the stream channel list tiles. -- Returning a Slidable widget with two CustomSlidableAction widgets - to delete a channel and show more options. These widgets come from the flutter_slidable package. -- Adding `onPressed` behaviour to call `showConfirmationBottomSheet` and `showChannelInfoModalBottomSheet`. These methods come from the **`stream_chat_flutter`** package. They have a few different on-tap callbacks you can supply, for example, `onViewInfoTap`. Alternatively, you can create custom dialog screens from scratch. -- Using the **StreamChannelListController** to perform actions, such as, `deleteChannel`. - -```dart -import 'package:flutter/material.dart'; -import 'package:flutter_slidable/flutter_slidable.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -void main() async { - final client = StreamChatClient( - 's2dxdhpxd94g', - ); - - await client.connectUser( - User(id: 'super-band-9'), - '''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''', - ); - - 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: ChannelListPage( - client: client, - ), - ); - } -} - -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: SlidableAutoCloseBehavior( - child: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - itemBuilder: (context, channels, index, tile) { - final channel = channels[index]; - final chatTheme = StreamChatTheme.of(context); - final backgroundColor = chatTheme.colorTheme.inputBg; - final canDeleteChannel = channel.ownCapabilities - .contains(PermissionType.deleteChannel); - return Slidable( - groupTag: 'channels-actions', - endActionPane: ActionPane( - extentRatio: canDeleteChannel ? 0.40 : 0.20, - motion: const BehindMotion(), - children: [ - CustomSlidableAction( - onPressed: (_) { - showChannelInfoModalBottomSheet( - context: context, - channel: channel, - onViewInfoTap: () { - Navigator.pop(context); - // Navigate to info screen - }, - ); - }, - backgroundColor: backgroundColor, - child: const Icon(Icons.more_horiz), - ), - if (canDeleteChannel) - CustomSlidableAction( - backgroundColor: backgroundColor, - child: StreamSvgIcon.delete( - color: chatTheme.colorTheme.accentError, - ), - onPressed: (_) async { - final res = await showConfirmationBottomSheet( - context, - title: 'Delete Conversation', - question: - 'Are you sure you want to delete this conversation?', - okText: 'Delete', - cancelText: 'Cancel', - icon: StreamSvgIcon.delete( - color: chatTheme.colorTheme.accentError, - ), - ); - if (res == true) { - await _controller.deleteChannel(channel); - } - }, - ), - ], - ), - child: tile, - ); - }, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ), - ); -} - -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) => Scaffold( - appBar: const StreamChannelHeader(), - body: Column( - children: const [ - Expanded( - child: StreamMessageListView(), - ), - StreamMessageInput(), - ], - ), - ); -} -``` - -The above is the complete sample, and all you need for a basic implementation. diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/_category_.json b/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/_category_.json deleted file mode 100644 index aa154b1968..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/03-custom_widgets/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Customizing Widgets" -} \ No newline at end of file diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/04-channel_list/_category_.json b/docusaurus/docs/Flutter/02-stream_chat_flutter/04-channel_list/_category_.json deleted file mode 100644 index 10c9cfefee..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/04-channel_list/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Channel List" -} \ No newline at end of file diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/04-channel_list/stream_channel_grid_view.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/04-channel_list/stream_channel_grid_view.mdx deleted file mode 100644 index 87ad4dc908..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/04-channel_list/stream_channel_grid_view.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: stream_channel_grid_view -title: StreamChannelGridView ---- - -A Widget For Displaying A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelGridView-class.html) - -### Background - -The `StreamChannelGridView` widget allows displaying a list of channels to a user in a `GridView`. - -:::note -Make sure to check the [StreamChannelListView](./stream_channel_list_view.mdx) documentation to know how to show results in a `ListView`. -::: - -### Basic Example - -Here is a basic example of the `StreamChannelGridView` widget. It consists of the main widget itself, a `StreamChannelListController` to control the list of channels and a callback to handle the tap of a channel. - -```dart -class ChannelGridPage extends StatefulWidget { - const ChannelGridPage({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - State createState() => _ChannelGridPageState(); -} - -class _ChannelGridPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelGridView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -This example by default displays the channels that a user is a part of. Now let's look at customizing -the widget. diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/04-channel_list/stream_channel_list_header.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/04-channel_list/stream_channel_list_header.mdx deleted file mode 100644 index b3e2916a4c..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/04-channel_list/stream_channel_list_header.mdx +++ /dev/null @@ -1,117 +0,0 @@ ---- -id: stream_channel_list_header -title: StreamChannelListHeader ---- - -A Header Widget For A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelListHeader-class.html) - -![](../../assets/channel_list_header.png) - -### Background - -A common pattern for most messaging apps is to show a list of Channels (chats) on the first screen -and navigate to an individual one on being clicked. On this first page where the list of channels are -displayed, it is usual to have functionality such as adding a new chat, display the user logged in, etc. - -To encapsulate all of this functionality into one widget, the Flutter SDK contains a `StreamChannelListHeader` -widget which provides these out of the box. - -### Basic Example - -This is a basic example of a page which has a `StreamChannelListView` and a `StreamChannelListHeader` to recreate a -common Channels Page. - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - appBar: const StreamChannelListHeader(), - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -### Customizing Parts Of The Header - -The header works like a `ListTile` widget. - -Use the `titleBuilder`, `subtitle`, `leading`, or `actions` parameters to substitute the widgets for your own. - -```dart -//... -StreamChannelListHeader( - subtitle: Text('My Custom Subtitle'), -), -``` - -![](../../assets/channel_list_header_custom_subtitle.png) - -The `titleBuilder` parameter helps you build different titles depending on the connection state: - -```dart -//... -StreamChannelListHeader( - titleBuilder: (context, status, client) { - switch(status) { - /// Return your title widget - } - }, -), -``` - -### Showing Connection State - -The `StreamChannelListHeader` can also display connection state below the tile which shows the user if they -are connected or offline, etc. on connection events. - -To enable this, use the `showConnectionStateTile` property. - -```dart -//... -StreamChannelListHeader( - showConnectionStateTile: true, -), -``` diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/04-channel_list/stream_channel_list_view.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/04-channel_list/stream_channel_list_view.mdx deleted file mode 100644 index 7912c5f7ed..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/04-channel_list/stream_channel_list_view.mdx +++ /dev/null @@ -1,106 +0,0 @@ ---- -id: stream_channel_list_view -title: StreamChannelListView ---- - -A Widget For Displaying A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelListView-class.html) - -![](../../assets/channel_list_view.png) - -### Background - -Channels are fundamental elements of Stream Chat and constitute shared spaces which allow users to -message each other. - -1:1 conversations and groups are both examples of channels, albeit with some (distinct/non-distinct) -differences. Displaying the list of channels that a user is a part of is a pattern present in most messaging apps. - -The `StreamChannelListView` widget allows displaying a list of channels to a user. By default, this is NOT -ONLY the channels that the user is a part of. This section goes into setting up and using a `StreamChannelListView` -widget. - -:::note -Make sure to check the [StreamChannelListController](../../04-stream_chat_flutter_core/stream_channel_list_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamChannelListView`. -::: - -### Basic Example - -Here is a basic example of the `StreamChannelListView` widget. It consists of the main widget itself, a `StreamChannelListController` to control the list of channels and a callback to handle the tap of a channel. - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -This example by default displays the channels that a user is a part of. Now let's look at customizing -the widget. - -### Customizing the Channel Preview - -A common aspect of the widget needed to be tweaked according to each app is the Channel Preview (the -Channel tile in the list). To do this, we use the `itemBuilder` parameter like this: - -```dart -StreamChannelListView( - ... - itemBuilder: (context, channels, index, defaultTile) { - return ListTile( - tileColor: Colors.amberAccent, - title: Center( - child: StreamChannelName(channel: channels[index]), - ), - ); - }, -), -``` - -Which gives you a new Channel preview in the list: - -![](../../assets/channel_preview.png) diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/06-message_list/_category_.json b/docusaurus/docs/Flutter/02-stream_chat_flutter/06-message_list/_category_.json deleted file mode 100644 index c125c49bfb..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/06-message_list/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Message List" -} \ No newline at end of file diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/06-message_list/stream_message_list_view.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/06-message_list/stream_message_list_view.mdx deleted file mode 100644 index c5a8067fb7..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/06-message_list/stream_message_list_view.mdx +++ /dev/null @@ -1,91 +0,0 @@ ---- -id: stream_message_list_view -title: StreamMessageListView ---- - -A Widget For Displaying A List Of Messages - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageListView-class.html) - -![](../../assets/message_list_view.png) - -### Background - -Every channel can contain a list of messages sent by users inside it. The `StreamMessageListView` widget -displays the list of messages inside a particular channel along with possible attachments and -other message attributes (if the message is pinned for example). This sets it apart from the `StreamMessageSearchListView` -which may not contain messages only from a single channel and is used to search for messages across -many. - -### Basic Example - -The `StreamMessageListView` shows the list of messages of the current channel. It has inbuilt support for -common messaging functionality: displaying and editing messages, adding / modifying reactions, support -for quoting messages, pinning messages, and more. - -An example of how you can use the `StreamMessageListView` is: - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: const StreamChannelHeader(), - body: Column( - children: [ - Expanded( - child: StreamMessageListView(), - ), - const StreamMessageInput(), - ], - ), - ); - } -} -``` - -### Enable Threads - -Threads are made of a parent message and replies linked to it. To enable threading, the SDK requires you -to supply a `threadBuilder` which will supply the page when the thread is clicked. - -```dart -StreamMessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, -), -``` - -![](../../assets/message_list_view_threads.png) - -The `StreamMessageListView` itself can render the thread by supplying the `parentMessage` parameter. - -```dart -StreamMessageListView( - parentMessage: parent, -), -``` - -### Building Custom Messages - -You can also supply your own implementation for displaying messages using the `messageBuilder` parameter. - -:::note -To customize the existing implementation, look at the `StreamMessageWidget` documentation instead. -::: - -```dart -StreamMessageListView( - messageBuilder: (context, details, messageList, defaultImpl) { - // Your implementation of the message here - // E.g: return Text(details.message.text ?? ''); - }, -), -``` diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/06-message_list/stream_message_search_grid_view.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/06-message_list/stream_message_search_grid_view.mdx deleted file mode 100644 index 06e6cdea2b..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/06-message_list/stream_message_search_grid_view.mdx +++ /dev/null @@ -1,60 +0,0 @@ ---- -id: stream_message_search_grid_view -title: StreamMessageSearchGridView ---- - -A Widget To Search For Messages Across Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageSearchGridView-class.html) - -### Background - -The `StreamMessageSearchGridView` widget allows displaying a list of searched messages in a `GridView`. - -:::note -Make sure to check the [StreamMessageSearchListView](./stream_message_search_list_view.mdx) documentation to know how to show results in a `ListView`. -::: - -### Basic Example - -```dart -class StreamMessageSearchPage extends StatefulWidget { - const StreamMessageSearchPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _StreamMessageSearchState(); -} - -class _StreamMessageSearchState extends State { - late final _controller = StreamMessageSearchListController( - client: widget.client, - limit: 20, - filter: Filter.in_( - 'members', - [StreamChat.of(context).user!.id], - ), - searchQuery: 'your query here', - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: StreamMessageSearchGridView( - controller: _controller, - itemBuilder: (context, values, index) { - // return your custom widget here - }, - ), - ); -} -``` diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/06-message_list/stream_message_search_list_view.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/06-message_list/stream_message_search_list_view.mdx deleted file mode 100644 index acb97e4e2a..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/06-message_list/stream_message_search_list_view.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -id: stream_message_search_list_view -title: StreamMessageSearchListView ---- - -A Widget To Search For Messages Across Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageSearchListView-class.html) - -![](../../assets/message_search_list_view.png) - -### Background - -Users in Stream Chat can have several channels and it can get hard to remember which channel has the -message they are searching for. As such, there needs to be a way to search for a message across multiple -channels. This is where `StreamMessageSearchListView` comes in. - -:::note -Make sure to check the [StreamMessageSearchListController](../../04-stream_chat_flutter_core/stream_message_search_list_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamMessageSearchListView`. -::: - -### Basic Example - -While the `StreamMessageListView` is tied to a certain `StreamChannel`, a `StreamMessageSearchListView` is not. - -```dart -class StreamMessageSearchPage extends StatefulWidget { - const StreamMessageSearchPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _StreamMessageSearchState(); -} - -class _StreamMessageSearchState extends State { - late final _controller = StreamMessageSearchListController( - client: widget.client, - limit: 20, - filter: Filter.in_( - 'members', - [StreamChat.of(context).user!.id], - ), - searchQuery: 'your query here', - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: StreamMessageSearchListView( - controller: _controller, - ), - ); -} -``` - -### Customize The Result Tiles - -You can use your own widget for the result items using the `itemBuilder` parameter. - -```dart -StreamMessageSearchListView( - // ... - itemBuilder: (context, responses, index, defaultWidget) { - return Text(responses[index].message.text); - }, -), -``` diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/06-message_list/stream_message_widget.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/06-message_list/stream_message_widget.mdx deleted file mode 100644 index e2da047751..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/06-message_list/stream_message_widget.mdx +++ /dev/null @@ -1,99 +0,0 @@ ---- -id: stream_message_widget -title: StreamMessageWidget ---- - -A Widget For Displaying Messages And Attachments - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageWidget-class.html) - -### Background - -There are several things that need to be displayed with text in a message in a modern messaging app: -attachments, highlights if the message is pinned, user avatars of the sender, etc. - -To encapsulate all of this functionality into one widget, the Flutter SDK contains a `StreamMessageWidget` -widget which provides these out of the box. - -### Basic Example (Modifying `StreamMessageWidget` in `StreamMessageListView`) - -Primarily, the `StreamMessageWidget` is used in the `StreamMessageListView`. To customize only a few properties -of the `StreamMessageWidget` without supplying all other properties, the `messageBuilder` builder supplies -a default implementation of the widget for us to modify. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: StreamMessageListView( - messageBuilder: (context, details, messageList, defaultMessageWidget) { - return defaultMessageWidget.copyWith( - showThreadReplyIndicator: false, - ); - }, - ), - ); - } -} -``` - -### Building A Custom Attachment - -When a custom attachment type (location, audio, etc.) is sent, the MessageWidget also needs to know -how to build it. For this purpose, we can use the `customAttachmentBuilders` parameter. - -As an example, if a message has a attachment type 'location', we do: - -```dart -StreamMessageWidget( - //... - customAttachmentBuilders: { - 'location': (context, message, attachments) { - var attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'], - attachments[0].extraData['longitude'], - ), - ); - - return WrapAttachmentWidget( - attachmentWidget: attachmentWidget, - attachmentShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - ); - } - }, -) -``` - -You can also override the builder for existing attachment types like `image` and `video`. - -### Show User Avatar For Messages - -You can decide to show, hide, or remove user avatars of the sender of the message. To do this, set -the `showUserAvatar` property like this: - -```dart -StreamMessageWidget( - //... - showUserAvatar = DisplayWidget.show, -) -``` - -### Reverse the message - -In most cases, `StreamMessageWidget` needs to be a different orientation depending upon if the sender is the -user or someone else. - -For this, we use the `reverse` parameter to change the orientation of the message: - -```dart -StreamMessageWidget( - //... - reverse = true, -) -``` diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/07-message_composer/_category_.json b/docusaurus/docs/Flutter/02-stream_chat_flutter/07-message_composer/_category_.json deleted file mode 100644 index d4e78a7ccc..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/07-message_composer/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Message Composer" -} \ No newline at end of file diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/07-message_composer/stream_message_input.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/07-message_composer/stream_message_input.mdx deleted file mode 100644 index f9bbee168c..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/07-message_composer/stream_message_input.mdx +++ /dev/null @@ -1,112 +0,0 @@ ---- -id: stream_message_input -title: StreamMessageInput ---- - -A Widget Dealing With Everything Related To Sending A Message - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageInput-class.html) - -![](../../assets/message_input.png) - -### Background - -In Stream Chat, we can send messages in a channel. However, sending a message isn't as simple as adding -a `TextField` and logic for sending a message. It involves additional processes like addition of media, -quoting a message, adding a custom command like a GIF board, and much more. Moreover, most apps also -need to customize the input to match their theme, overall color and structure pattern, etc. - -To do this, we created a `StreamMessageInput` widget which abstracts all expected functionality a modern input -needs - and allows you to use it out of the box. - -### Basic Example - -A `StreamChannel` is required above the widget tree in which the `StreamMessageInput` is rendered since the channel is -where the messages sent actually go. Let's look at a common example of how we could use the `StreamMessageInput`: - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: StreaChannelHeader(), - body: Column( - children: [ - Expanded( - child: StreamMessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, - ), - ), - StreamMessageInput(), - ], - ), - ); - } -} -``` - -It is common to put this widget in the same page of a `StreamMessageListView` as the bottom widget. - -:::note -Make sure to check the [StreamMessageInputController](../../04-stream_chat_flutter_core/stream_message_input_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamMessageInput`. -::: - -### Adding Custom Actions - -By default, the `StreamMessageInput` has two actions: one for attachments and one for commands like Giphy. -To add your own action, we use the `actions` parameter like this: - -```dart -StreamMessageInput( - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20, - color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, - ), - onTap: () { - // Do something here - }, - ), - ], -), -``` - -This will add on your action to the existing ones. - -### Disable Attachments - -To disable attachments being added to the message, set the `disableAttachments` parameter to true. - -```dart -StreamMessageInput( - disableAttachments: true, -), -``` - -### Changing Position Of MessageInput Components - -You can also change the position of the TextField, actions and 'send' button relative to each other. - -To do this, use the `actionsLocation` or `sendButtonLocation` parameters which help you decide the location -of the buttons in the input. - -For example, if we want the actions on the right and the send button inside the TextField, we can do: - -```dart -StreamMessageInput( - sendButtonLocation: SendButtonLocation.inside, - actionsLocation: ActionsLocation.right, -), -``` - -![](../../assets/message_input_change_position.png) diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/08-member_list/_category_.json b/docusaurus/docs/Flutter/02-stream_chat_flutter/08-member_list/_category_.json deleted file mode 100644 index 39e93fd5f2..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/08-member_list/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Member List" -} \ No newline at end of file diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/08-member_list/stream_member_grid_view.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/08-member_list/stream_member_grid_view.mdx deleted file mode 100644 index 9115d8448b..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/08-member_list/stream_member_grid_view.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -id: stream_member_grid_view -title: StreamMemberGridView ---- - -A widget for displaying and selecting members in a grid view. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMemberGridView-class.html) - -### Background - -The `StreamMemberGridView` widget allows displaying a list of members in a `GridView`. - -:::note -See the [StreamMemberListView](./stream_member_list_view.mdx) documentation for displaying members in a `ListView`. -::: - -### Basic Example - -```dart -class MemberGridPage extends StatefulWidget { - const MemberGridPage({ - super.key, - required this.client, - }); - - final Channel channel; - - @override - State createState() => _MemberGridPageState(); -} - -class _MemberGridPageState extends State { - late final _controller = StreamMemberListController( - channel: widget.channel, - limit: 25, - filter: Filter.and([ - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamMemberGridView( - controller: _controller, - onMemberTap: (member) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => Scaffold( - body: Center( - child: StreamUserAvatar( - user: member.user!, - ), - ), - ), - ), - ), - ), - ), - ); -} -``` diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/08-member_list/stream_member_list_view.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/08-member_list/stream_member_list_view.mdx deleted file mode 100644 index 0526db800c..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/08-member_list/stream_member_list_view.mdx +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: stream_member_list_view -title: StreamMemberListView ---- - -A widget for displaying and selecting members in a list view. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMemberListView-class.html) - -### Background - -A list of members is required for many different purposes, for example, showing a list of users in a Channel. The `StreamMemberListView` displays a list of members. - -:::note -Make sure to check the [StreamMemberListController](../../04-stream_chat_flutter_core/stream_member_list_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamMemberListView`. -::: - -### Basic Example - -```dart -class MemberListPage extends StatefulWidget { - const MemberListPage({super.key}); - - @override - State createState() => _MemberListPageState(); -} - -class _MemberListPageState extends State { - late final StreamMemberListController _memberListController = - StreamMemberListController( - channel: StreamChannel.of(context).channel, - limit: 25, - filter: Filter.and( - [Filter.notEqual('id', StreamChat.of(context).currentUser!.id)], - ), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - @override - Widget build(BuildContext context) { - return RefreshIndicator( - onRefresh: () => _memberListController.refresh(), - child: StreamMemberListView( - controller: _memberListController, - ), - ); - } -} -``` - -### Customize The Member Items - -You can use your own widget for the member items using the `itemBuilder` parameter. - -```dart -StreamMemberListView( - // ... - itemBuilder: (context, members, index, defaultWidget) { - return Text(members[index].user!.name); - }, -), -``` - -### Selecting Members - -The `StreamMemberListView` widget allows selecting members in a list. The `defaultWidget` returned can be customized to indicate that it has been selected. - -```dart -Set _selectedMembers = {}; - -StreamMemberListView( - controller: _memberListController, - itemBuilder: (context, members, index, defaultWidget) { - return defaultWidget.copyWith( - selected: _selectedMembers.contains(members[index]), - ); - }, - onMemberTap: (member) { - setState(() { - _selectedMembers.add(member); - }); - }, -); -``` diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/09-user_list/_category_.json b/docusaurus/docs/Flutter/02-stream_chat_flutter/09-user_list/_category_.json deleted file mode 100644 index c6715632dc..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/09-user_list/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "User List" -} \ No newline at end of file diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/09-user_list/stream_user_grid_view.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/09-user_list/stream_user_grid_view.mdx deleted file mode 100644 index b858cc4844..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/09-user_list/stream_user_grid_view.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -id: stream_user_grid_view -title: StreamUserGridView ---- - -A Widget For Displaying And Selecting Users - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamUserGridView-class.html) - -### Background - -The `StreamUserGridView` widget allows displaying a list of users in a `GridView`. - -:::note -Make sure to check the [StreamUserListView](./stream_user_list_view.mdx) documentation to know how to show results in a `ListView`. -::: - -### Basic Example - -```dart -class UserGridPage extends StatefulWidget { - const UserGridPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _UserGridPageState(); -} - -class _UserGridPageState extends State { - late final _controller = StreamUserListController( - client: widget.client, - limit: 25, - filter: Filter.and([ - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamUserGridView( - controller: _controller, - onMemberTap: (member) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => Scaffold( - body: Center( - child: StreamUserAvatar( - user: member.user!, - ), - ), - ), - ), - ), - ), - ), - ); -} -``` diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/09-user_list/stream_user_list_view.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/09-user_list/stream_user_list_view.mdx deleted file mode 100644 index d4e1a83eff..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/09-user_list/stream_user_list_view.mdx +++ /dev/null @@ -1,93 +0,0 @@ ---- -id: stream_user_list_view -title: StreamUserListView ---- - -A Widget For Displaying And Selecting Users - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamUserListView-class.html) - -![](../../assets/user_list_view.png) - -### Background - -A list of users is required for many different purposes: showing a list of users in a Channel, -selecting users to add in a channel, etc. The `StreamUserListView` displays a list -of users. - -:::note -Make sure to check the [StreamUserListController](../../04-stream_chat_flutter_core/stream_user_list_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamUserListView`. -::: - -### Basic Example - -```dart -class UserListPage extends StatefulWidget { - const UserListPage({super.key}); - - @override - State createState() => _UserListPageState(); -} - -class _UserListPageState extends State { - late final StreamUserListController _userListController = - StreamUserListController( - client: StreamChat.of(context).client, - limit: 25, - filter: Filter.and( - [Filter.notEqual('id', StreamChat.of(context).currentUser!.id)], - ), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - @override - Widget build(BuildContext context) { - return RefreshIndicator( - onRefresh: () => _userListController.refresh(), - child: StreamUserListView( - controller: _userListController, - ), - ); - } -} -``` - -### Customize The User Items - -You can use your own widget for the user items using the `itemBuilder` parameter. - -```dart -StreamUsersListView( - // ... - itemBuilder: (context, users, index, defaultWidget) { - return Text(users[index].name); - }, -), -``` - -### Selecting Users - -The `StreamUserListView` widget allows selecting users in a list. The `defaultWidget` returned can be customized to indicate that it has been selected. - -```dart -Set _selectedUsers = {}; - -StreamUserListView( - controller: _userListController, - itemBuilder: (context, users, index, defaultWidget) { - return defaultWidget.copyWith( - selected: _selectedUsers.contains(users[index]), - ); - }, - onUserTap: (user) { - setState(() { - _selectedUsers.add(user); - }); - }, -); -``` diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/getting_started.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/getting_started.mdx deleted file mode 100644 index 791fb7c316..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/getting_started.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -id: introduction -title: Getting Started ---- - -Understanding The UI Package Of The Flutter SDK - -### What function does `stream_chat_flutter` serve? - -The UI SDK (`stream_chat_flutter`) contains official Flutter components for Stream Chat, a service for building chat applications. - -While the Stream Chat service functions as the messaging backend and the LLC offers a straightforward integration for Flutter apps, our goal was to ensure the quick incorporation of Chat functionality into your application. To further simplify this process, we developed a dedicated UI package. - -The UI package is built on top of the low-level client and the core package and allows you to build a -full fledged app with either the inbuilt components, modify existing components, or easily add widgets -of your own to match your app's style better. - -### Add pub.dev dependency - -First, you need to add the `stream_chat_flutter` dependency to your `pubspec.yaml`. - -You can either run this command: - -```shell -flutter pub add stream_chat_flutter -``` - -OR - -Add this line in the dependencies section of your `pubspec.yaml` after substituting the latest version: - -```yaml -dependencies: - stream_chat_flutter: ^latest_version -``` - -You can find the package details on [pub.dev](https://pub.dev/packages/stream_chat_flutter). - -### Details On Platform Support - -As of the latest version, the`stream_chat_flutter` package (UI) added support for web, macOS, Windows, and Linux - on top of the original support for Android and iOS. It has, however, been possible to target desktop and web since Flutter added support for these platforms using the `stream_chat_flutter_core` (builder) and `stream_chat` (low-level client) packages - this remains unchanged. - -Please note that Flutter Web may have additional constraints due to not supporting all plugins that Stream Chat relies on. The respective plugin creators will address this over time. - -### Setup - -This section provides setup instructions for the respective platforms. - -#### Android - -The package uses [`photo_manager`](https://pub.dev/packages/photo_manager) to access the device's photo library. Follow [this wiki](https://pub.dev/packages/photo_manager#android-10-q-29) to fulfill the Android requirements. - -#### iOS - -The library uses [flutter file picker plugin](https://github.com/miguelpruivo/flutter_file_picker) to pick -files from the os. Follow [this wiki](https://github.com/miguelpruivo/flutter_file_picker/wiki/Setup#ios) to fulfill iOS requirements. - -Stream Chat also uses the [`video_player`](https://pub.dev/packages/video_player) package to play videos. Follow [this guide](https://pub.dev/packages/video_player#installation) to fulfill the requirements. - -Stream Chat uses the [`image_picker`](https://pub.dev/packages/image_picker) plugin. -Follow [these instructions](https://pub.dev/packages/image_picker#ios) to check the requirements. - -#### Web - -For the web, edit your `index.html` and add the following in the `` tag to allow the SDK to override the right-click behavior: - -```html - -``` - -#### macOS - -For macOS Stream Chat uses the [`file_selector`](https://pub.dev/packages/file_selector#macos) package. Follow [these instructions](https://pub.dev/packages/file_selector#macos) to check the requirements. - -You also need to add the following [entitlements](https://docs.flutter.dev/development/platform-integration/desktop#entitlements-and-the-app-sandbox) to `Release.entitlement` and `DebugProfile.entitlement`: - -```xml -com.apple.security.network.client - -com.apple.security.files.user-selected.read-write - -``` - -Which grants: - -- Internet permission -- File access permission diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/stream_channel_header.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/stream_channel_header.mdx deleted file mode 100644 index 9e22272cc6..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/stream_channel_header.mdx +++ /dev/null @@ -1,83 +0,0 @@ ---- -id: stream_channel_header -title: StreamChannelHeader ---- - -A Widget To Display Common Channel Details - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelHeader-class.html) - -![](../assets/channel_header.png) - -### Background - -When a user opens a channel, it is helpful to provide context of which channel they are in. This may -be in the form of a channel name or the users in the channel. Along with that, there also needs to be -a way for the user to look at more details of the channel (media, pinned messages, actions, etc.) and -preferably also a way to navigate back to where they came from. - -To encapsulate all of this functionality into one widget, the Flutter SDK contains a `StreamChannelHeader` -widget which provides these out of the box. - -### Basic Example - -Let's just add a `StreamChannelHeader` to a page with a `StreamMessageListView` and a `StreamMessageInput` to display -and send messages. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: const StreamChannelHeader(), - body: Column( - children: [ - Expanded( - child: StreamMessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, - ), - ), - const StreamMessageInput(), - ], - ), - ); - } -} -``` - -### Customizing Parts Of The Header - -The header works like a `ListTile` widget. - -Use the `title`, `subtitle`, `leading`, or `actions` parameters to substitute the widgets for your own. - -```dart -//... -StreamChannelHeader( - title: Text('My Custom Name'), -), -``` - -![](../assets/channel_header_custom_title.png) - -### Showing Connection State - -The `StreamChannelHeader` can also display connection state below the tile which shows the user if they -are connected or offline, etc. on connection events. - -To enable this, use the `showConnectionStateTile` property. - -```dart -//... -StreamChannelHeader( - showConnectionStateTile: true, -), -``` diff --git a/docusaurus/docs/Flutter/02-stream_chat_flutter/stream_chat_and_theming.mdx b/docusaurus/docs/Flutter/02-stream_chat_flutter/stream_chat_and_theming.mdx deleted file mode 100644 index 46153e246f..0000000000 --- a/docusaurus/docs/Flutter/02-stream_chat_flutter/stream_chat_and_theming.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: stream_chat_and_theming -title: Theming ---- - -Understanding How To Customize Widgets Using `StreamChatTheme` - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChatTheme-class.html) and [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChatThemeData-class.html) - -### Background - -Stream's UI SDK makes it easy for developers to add custom styles and attributes to our widgets. Like most Flutter frameworks, Stream exposes a dedicated widget for theming. - -Using `StreamChatTheme`, users can customize most aspects of our UI widgets by setting attributes using `StreamChatThemeData`. - -Similar to the `Theme` and `ThemeData` in Flutter, Stream Chat uses a top level [inherited widget](https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html) to provide theming information throughout your application. This can be optionally set at the top of your application tree or at a localized point in your widget sub-tree. - -If you'd like to customize the look and feel of Stream chat across your entire application, we recommend setting your theme at the top level. Conversely, users can customize specific screens or widgets by wrapping components in a `StreamChatTheme`. - -### A closer look at StreamChatThemeData - -Looking at the constructor for `StreamChatThemeData`, 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 `ChannelHeader`, `MessageInputs`, etc. have been broken up into smaller theme objects. - -```dart -factory StreamChatThemeData({ - Brightness? brightness, - TextTheme? textTheme, - ColorTheme? colorTheme, - StreamChannelListHeaderThemeData? channelListHeaderTheme, - StreamChannelPreviewThemeData? channelPreviewTheme, - StreamChannelHeaderThemeData? channelHeaderTheme, - StreamMessageThemeData? otherMessageTheme, - StreamMessageThemeData? ownMessageTheme, - StreamMessageInputThemeData? messageInputTheme, - Widget Function(BuildContext, User)? defaultUserImage, - PlaceholderUserImage? placeholderUserImage, - IconThemeData? primaryIconTheme, - List? reactionIcons, - StreamGalleryHeaderThemeData? imageHeaderTheme, - StreamGalleryFooterThemeData? imageFooterTheme, - StreamMessageListViewThemeData? messageListViewTheme, - }); -``` - -### Stream Chat Theme in use - -Let's take a look at customizing widgets using `StreamChatThemeData`. In the example below, we can change the default color theme to yellow and override the channel header's typography and colors. - -```dart -MaterialApp( - builder: (context, child) => StreamChat( - client: client, - streamChatThemeData: StreamChatThemeData( - colorTheme: StreamColorTheme.light( - accentPrimary: const Color(0xffffe072), - ), - channelHeaderTheme: const ChannelHeaderThemeData( - color: const Color(0xffd34646), - titleStyle: TextStyle( - color: Colors.white, - ), - ), - ), - child: child, - ), -); -``` - -We are creating this class at the very top of our widget tree using the `streamChatThemeData` parameter found in the `StreamChat` widget. - -![](../assets/using_theme.jpg) diff --git a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/_category_.json b/docusaurus/docs/Flutter/04-stream_chat_flutter_core/_category_.json deleted file mode 100644 index 0dff101427..0000000000 --- a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "State & Offline" -} \ No newline at end of file diff --git a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/introduction.mdx b/docusaurus/docs/Flutter/04-stream_chat_flutter_core/introduction.mdx deleted file mode 100644 index a59faf1017..0000000000 --- a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/introduction.mdx +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: introduction -title: Introduction ---- - -Understanding The Core Package Of The Flutter SDK - -This package provides business logic to fetch common things required for integrating Stream Chat into your application. -The core package allows more customisation and hence provides business logic but no UI components. -Please use the `stream_chat_flutter` package for the full fledged suite of UI components or `stream_chat` for the low-level client. - -### Background - -In the early days of the Flutter SDK, the SDK was only split into the LLC (`stream_chat`) and -the UI package (`stream_chat_flutter`). With this you could use a fully built interface with the UI package -or a fully custom interface with the LLC. However, we soon recognised the need for a third intermediary -package which made tasks like building and modifying a list of channels or messages easy but without -the complexity of using low level components. The Core package (`stream_chat_flutter_core`) is a manifestation -of the same idea and allows you to build an interface with Stream Chat without having to deal with -low level code and architecture as well as implementing your own theme and UI effortlessly. -Also, it has very few dependencies. - -We will now explore the components of this intermediary package and understand how it helps you build -the experience you want your users to have. - -The package primarily contains a bunch of controller classes. -Controllers are used to handle the business logic of the chat. You can use them together with our UI widgets, or you can even use them to build your own UI. - -* StreamChannelListController -* StreamUserListController -* StreamMessageSearchListController -* StreamMessageInputController -* LazyLoadScrollView -* PagedValueListenableBuilder - -This section goes into the individual core package widgets and their functional use. diff --git a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/lazy_load_scroll_view.mdx b/docusaurus/docs/Flutter/04-stream_chat_flutter_core/lazy_load_scroll_view.mdx deleted file mode 100644 index ad680bfbc9..0000000000 --- a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/lazy_load_scroll_view.mdx +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: lazy_load_scroll_view -title: Paging ---- - -A Widget For Building A Paginated List - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/LazyLoadScrollView-class.html) - -### Background - -The `LazyLoadScrollView` is a widget that helps you build a paginated list. -It provides callbacks to notify you when the list has been scrolled to the bottom and when the list has been scrolled to the top and other necessary callbacks. - -#### Callbacks - -* onStartOfPage: called when the list has been scrolled to the top of the page. - -* onEndOfPage: called when the list has been scrolled to the bottom of the page. - -* onPageScrollStart: called when the scroll of the list starts. - -* onPageScrollEnd: called when the scroll of the list ends. - -* onInBetweenOfPage: called when the list is not either at the top nor at the bottom of the page. - -### Basic Example - -Building a paginated list is a very common task. Here is an example of how to use the `LazyLoadScrollView` to build a simple list with pagination. - -```dart -LazyLoadScrollView( - onEndOfPage: _paginateData, - /// The child could be any widget which dispatches [ScrollNotification]s. - /// For example [ListView], [GridView] or [CustomScrollView]. - child: ListView.builder( - itemBuilder: (context, index) => _buildListTile, - ), -) -``` diff --git a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/message_list_core.mdx b/docusaurus/docs/Flutter/04-stream_chat_flutter_core/message_list_core.mdx deleted file mode 100644 index 7e988c1ae3..0000000000 --- a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/message_list_core.mdx +++ /dev/null @@ -1,71 +0,0 @@ ---- -id: message_list_core -title: Messages State ---- - -A Widget For Building A List Of Messages - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/MessageListCore-class.html) - -### Background - -The UI SDK of Stream Chat supplies a `MessageListView` class that builds a list of channels fetching -according to the filters and sort order given. However, in some cases, implementing novel UI is necessary -that cannot be done using the customization approaches given in the widget. - -To do this, we extracted the logic required for fetching channels into a 'Core' widget - a widget that -fetches channels in the expected way via the usual parameters but does not supply any UI and instead -exposes builders to build the UI in situations such as loading, empty data, errors, and on data received. - -### Basic Example - -`MessageListCore` is a simplified class that allows fetching a list of -messages while exposing UI builders. - -This allows you to construct your own UI while not having to -worry about the specific logic of fetching messages in a channel. - -A `MessageListController` is used to paginate data. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Column( - children: [ - Expanded( - child: MessageListCore( - emptyBuilder: (context) { - return const Center( - child: Text('Nothing here...'), - ); - }, - loadingBuilder: (context) { - return const Center( - child: CircularProgressIndicator(), - ); - }, - messageListBuilder: (context, list) { - return MessagesPage(list); - }, - errorBuilder: (context, err) { - return const Center( - child: Text('Error'), - ); - }, - ), - ), - ], - ), - ); - } -} -``` - -Make sure to have a `StreamChannel` ancestor in order to provide the -information about the channels. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/paged_value_listenable_builder.mdx b/docusaurus/docs/Flutter/04-stream_chat_flutter_core/paged_value_listenable_builder.mdx deleted file mode 100644 index 529c99a47e..0000000000 --- a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/paged_value_listenable_builder.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -id: paged_value_listenable_builder -title: Synchronize Paging Data ---- - -A Widget Whose Content Stays Synced With A `ValueNotifier` Of Type `PagedValue`. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/PagedValueListenableBuilder-class.html) - -### Background - -Given a `PagedValueNotifier` implementation and a [builder] which builds widgets from -concrete values of `PagedValue`, this class will automatically register itself as a -listener of the [PagedValueNotifier] and call the [builder] with updated values -when the value changes. - -### Basic Example - -```dart -class UserNameValueNotifier extends PagedValueNotifier { - UserNameValueNotifier() : super(const PagedValue.loading()); - - @override - Future doInitialLoad() async { - // Imitating network delay - await Future.delayed(const Duration(seconds: 1)); - value = const PagedValue( - items: ['Sahil', 'Salvatore', 'Reuben'], - - /// Passing the key to load the next page - nextPageKey: nextPageKey, - ); - } - - @override - Future loadMore(int nextPageKey) async { - // Imitating network delay - await Future.delayed(const Duration(seconds: 1)); - final previousItems = value.asSuccess.items; - final newItems = previousItems + ['Deven', 'Sacha', 'Gordon']; - value = PagedValue( - items: newItems, - // Passing nextPageKey as null to indicate - // that there are no more items. - nextPageKey: null, - ); - } -} - -class _MyHomePageState extends State { - final pagedValueNotifier = UserNameValueNotifier(); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Center( - child: PagedValueListenableBuilder( - builder: (context, value, child) { - // This builder will only get called when the _counter - // is updated. - return value.when( - (userNames, nextPageKey, error) => Column( - children: [ - const Text('Usernames:'), - Expanded( - child: ListView( - children: userNames.map(Text.new).toList(), - ), - ), - if (nextPageKey != null) - TextButton( - child: const Text('Load more'), - onPressed: () => pagedValueNotifier.loadMore(nextPageKey), - ), - ], - ), - loading: CircularProgressIndicator.new, - error: (e) => Text('Error: $e'), - ); - }, - valueListenable: pagedValueNotifier, - ), - ), - ); - } -} -``` diff --git a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/setup.mdx b/docusaurus/docs/Flutter/04-stream_chat_flutter_core/setup.mdx deleted file mode 100644 index f297484274..0000000000 --- a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/setup.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -id: setup -title: Setup ---- - -Understanding Setup For `stream_chat_flutter_core` - -### Add pub.dev dependency - -First, you need to add the `stream_chat_flutter_core` dependency to your pubspec.yaml - -You can either run this command: - -```shell -flutter pub add stream_chat_flutter_core -``` - -OR - -Add this line in the dependencies section of your pubspec.yaml after substituting latest version: - -```yaml -dependencies: - stream_chat_flutter_core: ^latest_version -``` - -You can find the package details on [pub.dev](https://pub.dev/packages/stream_chat_flutter_core). diff --git a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_channel_list_controller.mdx b/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_channel_list_controller.mdx deleted file mode 100644 index 9ffba46085..0000000000 --- a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_channel_list_controller.mdx +++ /dev/null @@ -1,152 +0,0 @@ ---- -id: stream_channel_list_controller -title: Channel State & Filtering ---- - -A Widget For Controlling A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamChannelListController-class.html) - -### Background - -The `StreamChannelListController` is a controller class that allows you to control a list of channels. -`StreamChannelListController` is a required parameter of the `StreamChannelListView` widget. -Check the [`StreamChannelListView` documentation](../02-stream_chat_flutter/04-channel_list/stream_channel_list_view.mdx) to read more about that. - -The `StreamChannelListController` also listens for various events and manipulates the current list of channels accordingly. -Passing a `StreamChannelListEventHandler` to the `StreamChannelListController` will allow you to customize this behaviour. - -### Basic Example - -Building a custom channel list is a very common task. Here is an example of how to use the `StreamChannelListController` to build a simple list with pagination. - -First of all we should create an instance of the `StreamChannelListController` and provide it with the `StreamChatClient` instance. -You can also add a `Filter`, a list of `SortOption`s and other pagination-related parameters. - -```dart -class _MyChannelListPageState extends State { - /// Controller used for loading more data and controlling pagination in - /// [StreamChannelListController]. - late final channelListController = StreamChannelListController( - client: StreamChatCore.of(context).client, - filter: Filter.and([ - Filter.equal('type', 'messaging'), - Filter.in_( - 'members', - [ - StreamChatCore.of(context).currentUser!.id, - ], - ), - ]), - ); - ... -} -``` - -Make sure you call `channelListController.doInitialLoad()` to load the initial data and `channelListController.dispose()` when the controller is no longer required. - -```dart -@override -void initState() { - channelListController.doInitialLoad(); - super.initState(); -} - -@override -void dispose() { - channelListController.dispose(); - super.dispose(); -} -``` - -The `StreamChannelListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of channels has changed. -You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest channels. - -```dart -@override -Widget build(BuildContext context) => Scaffold( - body: PagedValueListenableBuilder( - valueListenable: channelListController, - builder: (context, value, child) { - return value.when( - (channels, nextPageKey, error) => LazyLoadScrollView( - onEndOfPage: () async { - if (nextPageKey != null) { - channelListController.loadMore(nextPageKey); - } - }, - child: ListView.builder( - /// We're using the channels length when there are no more - /// pages to load and there are no errors with pagination. - /// In case we need to show a loading indicator or and error - /// tile we're increasing the count by 1. - itemCount: (nextPageKey != null || error != null) - ? channels.length + 1 - : channels.length, - itemBuilder: (BuildContext context, int index) { - if (index == channels.length) { - if (error != null) { - return TextButton( - onPressed: () { - channelListController.retry(); - }, - child: Text(error.message), - ); - } - return const CircularProgressIndicator(); - } - - final _item = channels[index]; - return ListTile( - title: Text(_item.name ?? ''), - subtitle: StreamBuilder( - stream: _item.state!.lastMessageStream, - initialData: _item.state!.lastMessage, - builder: (context, snapshot) { - if (snapshot.hasData) { - return Text(snapshot.data!.text!); - } - - return const SizedBox(); - }, - ), - onTap: () { - /// Display a list of messages when the user taps on - /// an item. We can use [StreamChannel] to wrap our - /// [MessageScreen] screen with the selected channel. - /// - /// This allows us to use a built-in inherited widget - /// for accessing our `channel` later on. - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: _item, - child: const MessageScreen(), - ), - ), - ); - }, - ); - }, - ), - ), - loading: () => const Center( - child: SizedBox( - height: 100, - width: 100, - child: CircularProgressIndicator(), - ), - ), - error: (e) => Center( - child: Text( - 'Oh no, something went wrong. ' - 'Please check your config. $e', - ), - ), - ); - }, - ), - ); -``` - -In this case we're using the [`LazyLoadScrollView`](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_channel_list_event_handler.mdx b/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_channel_list_event_handler.mdx deleted file mode 100644 index ee525d8d63..0000000000 --- a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_channel_list_event_handler.mdx +++ /dev/null @@ -1,54 +0,0 @@ ---- -id: stream_channel_list_event_handler -title: Channels Events ---- - -A Class To Customize The Event Handler For The StreamChannelListController. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamChannelListEventHandler-class.html) - -### Background - -A `StreamChannelListEventHandler` is a class that handles the events that are related to the channel list loaded by `StreamChannelListController`. -The `StreamChannelListController` automatically creates a `StreamChannelListEventHandler` internally and handles the events. In order to provide a custom -implementation of `StreamChannelListEventHandler`, you need to create a class that extends the `StreamChannelListEventHandler` class. - -### Basic Example - -There are 2 ways to provide a custom implementation of `StreamChannelListEventHandler`: - -* Create a class that extends the `StreamChannelListEventHandler` and pass it down to the controller. - -```dart -class MyCustomEventHandler extends StreamChannelListEventHandler { - @override - void onConnectionRecovered( - Event event, - StreamChannelListController controller, - ) { - // Write your own custom implementation here - } -} -``` - -Pass it down to the controller: - -```dart - late final listController = StreamChannelListController( - client: StreamChat.of(context).client, - eventHandler: MyCustomEventHandler(), - ); -``` - -* Mix the `StreamChannelListEventHandler` into your widget state. - -```dart -class _ChannelListPageState extends State { - - late final _listController = StreamChannelListController( - client: StreamChat.of(context).client, - eventHandler: MyCustomEventHandler(), - ); -} -``` - diff --git a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_chat_core.mdx b/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_chat_core.mdx deleted file mode 100644 index fb68fa1dea..0000000000 --- a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_chat_core.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -id: stream_chat_core -title: Chat Client ---- - -`StreamChatCore` is a version of `StreamChat` found in `stream_chat_flutter` that is decoupled from -theme and initialisations. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamChatCore-class.html) - -`StreamChatCore` is used to provide information about the chat client to the widget tree. -This Widget is used to react to life cycle changes and system updates. -When the app goes into the background, the web socket connection is automatically closed and when it goes back to foreground the connection is opened again. - -Like the `StreamChat` widget in the higher level UI package, the `StreamChatCore` widget should -be on the top level before using any Stream functionality: - -```dart -return MaterialApp( - title: 'Stream Chat Core Example', - home: HomeScreen(), - builder: (context, child) => StreamChatCore( - client: client, - child: child, - ), - ); -``` diff --git a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_member_list_controller.mdx b/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_member_list_controller.mdx deleted file mode 100644 index 192cf13878..0000000000 --- a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_member_list_controller.mdx +++ /dev/null @@ -1,111 +0,0 @@ ---- -id: stream_member_list_controller -title: Members State ---- - -A widget for controlling a list of members. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamMemberListController-class.html) - -### Background - -The `StreamMemberListController` is a controller class that allows you to control a list of users. -`StreamMemberListController` is a required parameter of the `StreamMemberListView` widget. -Check the [`StreamMemberListView` documentation](../02-stream_chat_flutter/04-channel_list/stream_channel_list_view.mdx) to read more about that. - -### Basic Example - -Building a custom member list is a very common task. Here is an example of how to use the `StreamMemberListController` to build a simple list with pagination. - -First, create an instance of the `StreamMemberListController` and provide it with the `StreamChatClient` instance. -You can also add a `Filter`, a list of `SortOption`s, and other pagination-related parameters. - -```dart -class MemberListPageState extends State { - /// Controller used for loading more data and controlling pagination in - /// [StreamMemberListController]. - late final memberListController = StreamMemberListController( - channel: StreamChannel.of(context).channel, - ); -``` - -Make sure you call `memberListController.doInitialLoad()` to load the initial data and `memberListController.dispose()` when the controller is no longer required. - -```dart -@override -void initState() { - memberListController.doInitialLoad(); - super.initState(); -} - -@override -void dispose() { - memberListController.dispose(); - super.dispose(); -} -``` - -The `StreamMemberListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of members has changed. -You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest members. - -```dart -@override -Widget build(BuildContext context) => Scaffold( - body: PagedValueListenableBuilder( - valueListenable: memberListController, - builder: (context, value, child) { - return value.when( - (members, nextPageKey, error) => LazyLoadScrollView( - onEndOfPage: () async { - if (nextPageKey != null) { - memberListController.loadMore(nextPageKey); - } - }, - child: ListView.builder( - /// We're using the members length when there are no more - /// pages to load and there are no errors with pagination. - /// In case we need to show a loading indicator or and error - /// tile we're increasing the count by 1. - itemCount: (nextPageKey != null || error != null) - ? members.length + 1 - : members.length, - itemBuilder: (BuildContext context, int index) { - if (index == members.length) { - if (error != null) { - return TextButton( - onPressed: () { - memberListController.retry(); - }, - child: Text(error.message), - ); - } - return const CircularProgressIndicator(); - } - - final _item = members[index]; - return ListTile( - title: Text(_item.user?.name ?? ''), - ); - }, - ), - ), - loading: () => const Center( - child: SizedBox( - height: 100, - width: 100, - child: CircularProgressIndicator(), - ), - ), - error: (e) => Center( - child: Text( - 'Oh no, something went wrong. ' - 'Please check your config. $e', - ), - ), - ); - }, - ), - ); -``` - -In this case, we're using the [LazyLoadScrollView](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list. diff --git a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_message_input_controller.mdx b/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_message_input_controller.mdx deleted file mode 100644 index 94e2b2561a..0000000000 --- a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_message_input_controller.mdx +++ /dev/null @@ -1,88 +0,0 @@ ---- -id: stream_message_input_controller -title: Message Composer State ---- - -A Widget For Controlling A Message Input - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamMessageInputController-class.html) - -### Background - -The `StreamMessageInputController` is a controller class that embed the business logic to compose a message. -`StreamMessageInputController` is a parameter of the `StreamMessageInput` widget. -Check the [`StreamMessageInput` documentation](../02-stream_chat_flutter/07-message_composer/stream_message_input.mdx) to read more about that. - -### Basic Example - -Building a custom message input is a common task. Here is an example of how to use the `StreamMessageInputController` to build a simple custom message input widget. - -First of all we should create an instance of the `StreamMessageInputController`. - -```dart -class MessageScreenState extends State { - final StreamMessageInputController messageInputController = StreamMessageInputController(); -``` - -Make sure you call `messageInputController.dispose()` when the controller is no longer required. - -```dart -@override -void dispose() { - messageInputController.dispose(); - super.dispose(); -} -``` - -The `StreamMessageInputController` is basically a `ValueNotifier` that notifies you when the message being composed has changed. -You can use a `ValueListenableBuilder` to build your UI depending on the latest message. -For a very simple message input you could even pass the `messageInputController.textEditingController` to your `TextField` and set the `onChanged` callback. - -```dart -... -Padding( - padding: const EdgeInsets.all(8), - child: Row( - children: [ - Expanded( - child: TextField( - controller: messageInputController.textFieldController, - onChanged: (s) => messageInputController.text = s, - decoration: const InputDecoration( - hintText: 'Enter your message', - ), - ), - ), - Material( - type: MaterialType.circle, - color: Colors.blue, - clipBehavior: Clip.hardEdge, - child: InkWell( - onTap: () async { - if (messageInputController.message.text?.isNotEmpty == - true) { - await channel.sendMessage( - messageInputController.message, - ); - messageInputController.clear(); - if (context.mounted) { - _updateList(); - } - } - }, - child: const Padding( - padding: EdgeInsets.all(8), - child: Center( - child: Icon( - Icons.send, - color: Colors.white, - ), - ), - ), - ), - ), - ], - ), -), -... -``` diff --git a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_message_search_list_controller.mdx b/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_message_search_list_controller.mdx deleted file mode 100644 index 108f2d425a..0000000000 --- a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_message_search_list_controller.mdx +++ /dev/null @@ -1,128 +0,0 @@ ---- -id: stream_message_search_list_controller -title: Message Search State ---- - -A Widget For Controlling A List Of Searched Messages - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamMessageSearchListController-class.html) - -### Background - -The `StreamMessageSearchListController` is a controller class that allows you to control a list of searched messages. -`StreamMessageSearchListController` is a required parameter of the `StreamMessageSearchListView` widget. -Check the [`StreamMessageSearchListView` documentation](../02-stream_chat_flutter/06-message_list/stream_message_search_list_view.mdx) to read more about that. - -### Basic Example - -Building a custom message search feature is a common task. Here is an example of how to use the `StreamMessageSearchListController` to build a simple search list with pagination. - -First of all we should create an instance of the `StreamMessageSearchListController` and provide it with the `StreamChatClient` instance. -We can then add a filter to only get the channels that the current user is a part of. -You can also add a list of `SortOption`s and other pagination-related parameters. - -```dart -class SearchListPageState extends State { - /// Controller used for loading more data and controlling pagination in - /// [StreamMessageSearchListController]. - late final messageSearchListController = StreamMessageSearchListController( - client: StreamChatCore.of(context).client, - filter: Filter.in_('members', [StreamChat.of(context).currentUser!.id]), - ); -``` - -Make sure you call `messageSearchListController.doInitialLoad()` to load the initial data and `messageSearchListController.dispose()` when the controller is no longer required. - -```dart -@override -void initState() { - messageSearchListController.doInitialLoad(); - super.initState(); -} - -@override -void dispose() { - messageSearchListController.dispose(); - super.dispose(); -} -``` - -The `StreamMessageSearchListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of responses has changed. -You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest responses. - -```dart -@override -Widget build(BuildContext context) => Scaffold( - body: Column( - children: [ - TextField( - /// This is just a sample implementation of a search field. - /// In a real-world app you should throttle the search requests. - /// You can use our library [rate_limiter](https://pub.dev/packages/rate_limiter). - onChanged: (s) { - messageSearchListController..searchQuery = s..doInitialLoad(); - }, - ), - Expanded( - child: PagedValueListenableBuilder( - valueListenable: messageSearchListController, - builder: (context, value, child) { - return value.when( - (responses, nextPageKey, error) => LazyLoadScrollView( - onEndOfPage: () async { - if (nextPageKey != null) { - messageSearchListController.loadMore(nextPageKey); - } - }, - child: ListView.builder( - /// We're using the responses length when there are no more - /// pages to load and there are no errors with pagination. - /// In case we need to show a loading indicator or and error - /// tile we're increasing the count by 1. - itemCount: (nextPageKey != null || error != null) - ? responses.length + 1 - : responses.length, - itemBuilder: (BuildContext context, int index) { - if (index == responses.length) { - if (error != null) { - return TextButton( - onPressed: () { - messageSearchListController.retry(); - }, - child: Text(error.message), - ); - } - return const CircularProgressIndicator(); - } - - final _item = responses[index]; - return ListTile( - title: Text(_item.channel?.name ?? ''), - subtitle: Text(_item.message.text ?? ''), - ); - }, - ), - ), - loading: () => const Center( - child: SizedBox( - height: 100, - width: 100, - child: CircularProgressIndicator(), - ), - ), - error: (e) => Center( - child: Text( - 'Oh no, something went wrong. ' - 'Please check your config. $e', - ), - ), - ); - }, - ), - ), - ], - ), - ); -``` - -In this case we're using the [`LazyLoadScrollView`](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_user_list_controller.mdx b/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_user_list_controller.mdx deleted file mode 100644 index 7ce1d9a7fc..0000000000 --- a/docusaurus/docs/Flutter/04-stream_chat_flutter_core/stream_user_list_controller.mdx +++ /dev/null @@ -1,111 +0,0 @@ ---- -id: stream_user_list_controller -title: Users State & Filtering ---- - -A Widget For Controlling A List Of Users - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamUserListController-class.html) - -### Background - -The `StreamUserListController` is a controller class that allows you to control a list of users. -`StreamUserListController` is a required parameter of the `StreamUserListView` widget. -Check the [`StreamUserListView` documentation](../02-stream_chat_flutter/09-user_list/stream_user_list_view.mdx) to read more about that. - -### Basic Example - -Building a custom user list is a very common task. Here is an example of how to use the `StreamUserListController` to build a simple list with pagination. - -First of all we should create an instance of the `StreamUserListController` and provide it with the `StreamChatClient` instance. -You can also add a `Filter`, a list of `SortOption`s and other pagination-related parameters. - -```dart -class UserListPageState extends State { - /// Controller used for loading more data and controlling pagination in - /// [StreamUserListController]. - late final userListController = StreamUserListController( - client: StreamChatCore.of(context).client, - ); -``` - -Make sure you call `userListController.doInitialLoad()` to load the initial data and `userListController.dispose()` when the controller is no longer required. - -```dart -@override -void initState() { - userListController.doInitialLoad(); - super.initState(); -} - -@override -void dispose() { - userListController.dispose(); - super.dispose(); -} -``` - -The `StreamUserListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of users has changed. -You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest users. - -```dart -@override -Widget build(BuildContext context) => Scaffold( - body: PagedValueListenableBuilder( - valueListenable: userListController, - builder: (context, value, child) { - return value.when( - (users, nextPageKey, error) => LazyLoadScrollView( - onEndOfPage: () async { - if (nextPageKey != null) { - userListController.loadMore(nextPageKey); - } - }, - child: ListView.builder( - /// We're using the users length when there are no more - /// pages to load and there are no errors with pagination. - /// In case we need to show a loading indicator or and error - /// tile we're increasing the count by 1. - itemCount: (nextPageKey != null || error != null) - ? users.length + 1 - : users.length, - itemBuilder: (BuildContext context, int index) { - if (index == users.length) { - if (error != null) { - return TextButton( - onPressed: () { - userListController.retry(); - }, - child: Text(error.message), - ); - } - return const CircularProgressIndicator(); - } - - final _item = users[index]; - return ListTile( - title: Text(_item.name), - ); - }, - ), - ), - loading: () => const Center( - child: SizedBox( - height: 100, - width: 100, - child: CircularProgressIndicator(), - ), - ), - error: (e) => Center( - child: Text( - 'Oh no, something went wrong. ' - 'Please check your config. $e', - ), - ), - ); - }, - ), - ); -``` - -In this case we're using the [`LazyLoadScrollView`](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/05-guides/01-understanding_filters.mdx b/docusaurus/docs/Flutter/05-guides/01-understanding_filters.mdx deleted file mode 100644 index 152a8a8fee..0000000000 --- a/docusaurus/docs/Flutter/05-guides/01-understanding_filters.mdx +++ /dev/null @@ -1,193 +0,0 @@ ---- -id: understanding_filters -title: Filters ---- - -Understanding Filters - -### Introduction - -Filters are used to get a specific subset of objects (channels, users, messages, members, etc) which -fit the conditions specified. Earlier versions of the SDK contained String-based filters which are now replaced by type-safe -filters. This guide aims to explain the different types of filters and how to use them. - -### Types Of Filters - -#### Filter.equal - -The 'equal' filter gets the objects where the given key has the specified value. - -```dart -Filter.equal('type', 'messaging'), -``` - -#### Filter.notEqual - -The `notEqual` filter gets the objects where the given key does not have the specified value. - -```dart -Filter.notEqual('type', 'messaging'), -``` - -#### Filter.greater - -The 'greater' filter gets the objects where the given key has a higher value than the specified value. - -```dart -Filter.greater('count', 5), -``` - -#### Filter.greaterOrEqual - -The 'greaterOrEqual' filter gets the objects where the given key has an equal or higher value than the specified value. - -```dart -Filter.greaterOrEqual('count', 5), -``` - -#### Filter.less - -The 'less' filter gets the objects where the given key has a lesser value than the specified value. - -```dart -Filter.less('count', 5), -``` - -#### Filter.lessOrEqual - -The 'lessOrEqual' filter gets the objects where the given key has a lesser or equal value than the specified value. - -```dart -Filter.lessOrEqual('count', 5), -``` - -#### Filter.in_ - -The `in_` filter allows getting objects where the key matches any in a specified array. - -```dart -Filter.in_('members', [user.id]) -``` - -:::note -Since 'in' is a keyword in Dart, the filter has an underscore added. This does not apply to the `notIn` -keyword. -::: - -#### Filter.notIn - -The `notIn` filter allows getting objects where the key matches none in a specified array. - -```dart -Filter.notIn('members', [user.id]) -``` - -#### Filter.query - -The 'query' filter matches values by performing text search with the specified value. - -```dart -Filter.query('name', 'demo') -``` - -#### Filter.autoComplete - -The 'autoComplete' filter matches values with the specified prefix. - -```dart -Filter.autoComplete('name', 'demo') -``` - -#### Filter.exists - -The 'exists' filter matches values that exist, or don't exist, based on the specified boolean value. - -```dart -Filter.exists('name') -``` - -#### Filter.notExists - -The `notExists` filter checks if the specified key doesn't exist. This is a simplified call to `Filter.exists` -with the value set to false. - -```dart -Filter.notExists('name') -``` - -#### Filter.contains - -The 'contains' filter matches any list that contains the specified value. - -```dart -Filter.contains('teams', 'red') -``` - -#### Filter.empty - -The 'empty' filter constructor returns an empty filter. It's the equivalent of an empty map `{}`; - -```dart -Filter.empty(); -``` - -#### Filter.raw - -The 'raw' filter constructor lets you specify a raw filter. We suggest using this only if you can't manage to build what you want using the other constructors. - -```dart -Filter.raw(value: { - 'members': [ - ..._selectedUsers.map((e) => e.id), - chatState.currentUser!.id, - ], - 'distinct': true, -}); -``` - -#### Filter.custom - -The 'custom' filter is used to create a custom filter in case it does not exists or it's not been added to the SDK yet. -Note that the filter must be supported by the Stream backend in order to work. - -```dart -Filter.custom( - operator: '\$max', - value: 10, -) -``` - -### Group Queries - -#### Filter.and - -The 'and' operator combines multiple queries. - -```dart -final filter = Filter.and([ - Filter.equal('type', 'messaging'), - Filter.in_('members', [user.id]) -]) -``` - -#### Filter.or - -Combines the provided filters and matches the values matched by at least one of the filters. - -```dart -final filter = Filter.or([ - Filter.in_('bannedUsers', [user.id]), - Filter.in_('shadowBannedUsers', [user.id]) -]) -``` - -#### Filter.nor - -Combines the provided filters and matches the values not matched by all the filters. - -```dart -final filter = Filter.nor([ - Filter.in_('bannedUsers', [user.id]), - Filter.in_('shadowBannedUsers', [user.id]) -]) -``` diff --git a/docusaurus/docs/Flutter/05-guides/02-adding_local_data_persistence.mdx b/docusaurus/docs/Flutter/05-guides/02-adding_local_data_persistence.mdx deleted file mode 100644 index 3943b1f972..0000000000 --- a/docusaurus/docs/Flutter/05-guides/02-adding_local_data_persistence.mdx +++ /dev/null @@ -1,75 +0,0 @@ ---- -id: adding_local_data_persistence -title: Offline Support ---- - -Adding Local Data Persistence for Offline Support - -### Introduction - -Most messaging apps need to work regardless of whether the app is currently connected to the internet. -Local data persistence stores the fetched data from the backend on a local SQLite database using the -moor package in Flutter. All packages in the SDK can use local data persistence to store messages -across multiple platforms. - -### Implementation - -To add data persistence you can extend the class ChatPersistenceClient and pass an instance to the StreamChatClient. - -```dart -class CustomChatPersistentClient extends ChatPersistenceClient { -... -} - -final client = StreamChatClient( - apiKey ?? kDefaultStreamApiKey, - logLevel: Level.INFO, -)..chatPersistenceClient = CustomChatPersistentClient(); -``` - -We provide an official persistent client in the [`stream_chat_persistence`](https://pub.dev/packages/stream_chat_persistence) -package that works using the library [moor](https://moor.simonbinder.eu), an SQLite ORM. - -Add this to your package's `pubspec.yaml` file, using the latest version. - -```yaml -dependencies: - stream_chat_persistence: ^latest_version -``` - -You should then run `flutter packages get` - -The usage is pretty simple. - -1. Create a new instance of `StreamChatPersistenceClient` providing `logLevel` and `connectionMode` - -```dart -final chatPersistentClient = StreamChatPersistenceClient( - logLevel: Level.INFO, - connectionMode: ConnectionMode.background, -); -``` - -2. Pass the instance to the official `StreamChatClient` - -```dart - final client = StreamChatClient( - apiKey ?? kDefaultStreamApiKey, - logLevel: Level.INFO, - )..chatPersistenceClient = chatPersistentClient; -``` - -And you are ready to go... - -Note that passing `ConnectionMode.background` the database uses a background isolate to unblock the main thread. -The `StreamChatClient` uses the `chatPersistentClient` to synchronize the database with the newest -information every time it receives new data about channels/messages/users. - -### Multi-user - -The DB file is named after the `userId`, so if you instantiate a client using a different `userId` you will use a different database. -Calling `client.disconnectUser(flushChatPersistence: true)` flushes all current database data. - -### Updating/deleting/sending a message while offline - -The information about the action is saved in offline storage. When the client returns online, everything is retried. diff --git a/docusaurus/docs/Flutter/05-guides/03-user_token_generation_with_firebase_auth.mdx b/docusaurus/docs/Flutter/05-guides/03-user_token_generation_with_firebase_auth.mdx deleted file mode 100644 index 4292f7fb09..0000000000 --- a/docusaurus/docs/Flutter/05-guides/03-user_token_generation_with_firebase_auth.mdx +++ /dev/null @@ -1,454 +0,0 @@ ---- -id: token_generation_with_firebase -title: Authentication ---- - -Securely generate Stream Chat user tokens using Firebase Authentication and Cloud Functions. - -:::note -This guide assumes that you are familiar with Firebase Authentication and Cloud Functions for Flutter and using the Flutter Stream Chat SDK. -::: - -### Introduction - -In this guide, you'll explore how you can use Firebase Auth as an authentication provider and create Firebase Cloud functions to securely -generate Stream Chat user tokens. - -You will use Stream's [NodeJS client](https://getstream.io/chat/docs/node/?language=javascript) for Stream account creation and -token generation, and [Flutter Cloud Functions for Firebase](https://firebase.google.com/docs/functions/callable?gen=2nd#dart) to invoke the cloud functions -from your Flutter app. - -Stream supports several different [backend clients](https://getstream.io/chat/sdk/#backend-clients) to integrate with your server. This guide only shows an easy way to integrate Stream Chat authentication using Firebase and Flutter. - -### Flutter Firebase - -See the [Flutter Firebase getting started](https://firebase.google.com/docs/flutter/setup) docs for setup and installation instructions. - -You will also need to add the [Flutter Firebase Authentication](https://firebase.google.com/docs/auth/flutter/start), and [Flutter Firebase Cloud Functions](https://firebase.google.com/docs/functions/callable?gen=2nd#dart) packages to your app. Depending on the platform that you target, there may be specific configurations that you need to do. - -#### Starting Code - -The following code shows a basic application with **FirebaseAuth** and **FirebaseFunctions**. - -You will extend this later to execute cloud functions. - -```dart -import 'package:cloud_functions/cloud_functions.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:firebase_auth/firebase_auth.dart' as firebase_auth; -import 'package:flutter/material.dart'; -import 'dart:async'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - await Firebase.initializeApp(); - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: Scaffold( - body: Auth(), - ), - ); - } -} - -class Auth extends StatefulWidget { - const Auth({super.key}); - - @override - _AuthState createState() => _AuthState(); -} - -class _AuthState extends State { - late firebase_auth.FirebaseAuth auth; - late FirebaseFunctions functions; - - @override - void initState() { - super.initState(); - auth = firebase_auth.FirebaseAuth.instance; - functions = FirebaseFunctions.instance; - } - - final email = 'test@getstream.io'; - final password = 'password'; - - Future createAccount() async { - // Create Firebase account - await auth.createUserWithEmailAndPassword(email: email, password: password); - print('Firebase account created'); - } - - Future signIn() async { - // Sign in with Firebase - await auth.signInWithEmailAndPassword(email: email, password: password); - print('Firebase signed in'); - } - - Future signOut() async { - // Revoke Stream chat token. - final callable = functions.httpsCallable('revokeStreamUserToken'); - await callable(); - print('Stream user token revoked'); - } - - @override - Widget build(BuildContext context) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - AuthenticationState( - streamUser: auth.authStateChanges().map( - (firebaseUser) => firebaseUser != null - ? User( - id: firebaseUser.uid, - // Map other user fields here - ) - : null, - ), - ), - ElevatedButton( - onPressed: createAccount, - child: const Text('Create account'), - ), - ElevatedButton( - onPressed: signIn, - child: const Text('Sign in'), - ), - ElevatedButton( - onPressed: signOut, - child: const Text('Sign out'), - ), - ], - ), - ); - } -} - -class AuthenticationState extends StatelessWidget { - const AuthenticationState({ - super.key, - required this.streamUser, - }); - - final Stream streamUser; - - @override - Widget build(BuildContext context) { - return StreamBuilder( - stream: streamUser, - builder: (context, snapshot) { - if (snapshot.hasData) { - return (snapshot.data != null) - ? const Text('Authenticated') - : const Text('Not Authenticated'); - } - return const Text('Not Authenticated'); - }, - ); - } -} - -``` - -Running the above will give this: - -![](../assets/authentication_demo_app.jpg) - -The `Auth` widget handles all of the authentication logic. It initializes a `FirebaseAuth.instance` and uses that -in the `createAccount`, `signIn` and `signOut` methods. There is a button to invoke each of these methods. - -The `FirebaseFunctions.instance` will be used later in this guide. - -The `AuthenticationState`` widget listens to `auth.authStateChanges()` (mapped to Stream's `User`) -to display a message indicating if a user is authenticated. - -### Firebase Cloud Functions - -Firebase Cloud Functions allows you to extend Firebase with custom operations that an event can trigger: -- **Internal event**: For example, when creating a new Firebase account this is automatically triggered. -- **External event**: For example, directly calling a cloud function from your Flutter application. - -To set up your local environment to deploy cloud functions, please see the -[Cloud Functions getting started](https://firebase.google.com/docs/flutter/setup) docs. - -After initializing your project with cloud functions, you should have a **functions** folder in your project, including a `package.json` file. - -There should be two dependencies already added, **firebase-admin** and **firebase-functions**. You will also need to add the **stream-chat** dependency. - -Navigate to the **functions** folder and run `npm install stream-chat --save-prod`. - -This will install the node module and add it as a dependency to `package.json`. - -Now open `index.js` and add the following (this is the complete example): - -```js -const StreamChat = require('stream-chat').StreamChat; -const functions = require("firebase-functions"); -const admin = require("firebase-admin"); - -admin.initializeApp(); - -const serverClient = StreamChat.getInstance(functions.config().stream.key, functions.config().stream.secret); - - -// When a user is deleted from Firebase their associated Stream account is also deleted. -exports.deleteStreamUser = functions.auth.user().onDelete((user, context) => { - return serverClient.deleteUser(user.uid); -}); - -// Create a Stream user and return auth token. -exports.createStreamUserAndGetToken = functions.https.onCall(async (data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - // Create user using the serverClient. - await serverClient.upsertUser({ - id: context.auth.uid, - name: context.auth.token.name, - email: context.auth.token.email, - image: context.auth.token.image, - }); - - /// Create and return user auth token. - return serverClient.createToken(context.auth.uid); - } catch (err) { - console.error(`Unable to create user with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not create Stream user"); - } - } -}); - -// Get Stream user token. -exports.getStreamUserToken = functions.https.onCall((data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - return serverClient.createToken(context.auth.uid); - } catch (err) { - console.error(`Unable to get user token with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not get Stream user"); - } - } -}); - -// Revoke the authenticated user's Stream chat token. -exports.revokeStreamUserToken = functions.https.onCall((data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - return serverClient.revokeUserToken(context.auth.uid); - } catch (err) { - console.error(`Unable to revoke user token with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not get Stream user"); - } - } -}); - -``` - -First, you import the necessary packages and call `admin.initializeApp();` to set up Firebase cloud functions. - -Next, you initialize the **StreamChat** server client by calling `StreamChat.getInstance`. This function requires your Stream app's -**token** and **secret**. You can get this from the Stream Dashboard for your app. - -Set these values as environment data on Firebase Functions. - -```bash - firebase functions:config:set stream.key="app-key" stream.secret="app-secret" -``` - -*Replace **app-key** and **app-secret** with the values for your Stream app.* - -This creates an object of **stream** with properties **key** and **secret**. To access this environment -data use `functions.config().stream.key` and `functions.config().stream.secret`. - -See the [Firebase environment configuration](https://firebase.google.com/docs/functions/config-env) -documentation for additional information. - -To deploy these functions to Firebase, run: - -```bash -firebase deploy --only functions -``` - -### Create a Stream User and Get the User's Token - -In the `createStreamUserAndGetToken` cloud function you create an `onCall` HTTPS handler, which exposes -a cloud function that can be invoked from your Flutter app. - -```js -// Create a Stream user and return auth token. -exports.createStreamUserAndGetToken = functions.https.onCall(async (data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - // Create user using the serverClient. - await serverClient.upsertUser({ - id: context.auth.uid, - name: context.auth.token.name, - email: context.auth.token.email, - image: context.auth.token.image, - }); - - /// Create and return user auth token. - return serverClient.createToken(context.auth.uid); - } catch (err) { - console.error(`Unable to create user with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not create Stream user"); - } - } -}); -``` - -This function first does a check to see that the client that calls it is authenticated, -by ensuring that `context.auth` is not null. If it is null, then it throws an `HttpsError` with a descriptive -message. This error can be caught in your Flutter application. - -If the caller is authenticated the function proceeds to use the `serverClient` to create a new Stream Chat -user by calling the `upsertUser` method and passing in some user data. It uses the authenticated caller's **`uid`** as an **id**. - -After the user is created it generates a token for that user. This token is then returned to the caller. - -To call this from Flutter, you will need to use the `cloud_functions` package. - -Update the **`createAccount`** method in your Flutter code to the following: - -```dart -Future createAccount() async { - // Create Firebase account - await auth.createUserWithEmailAndPassword(email: email, password: password); - print('Firebase account created'); - - // Create Stream user and get token - final callable = functions.httpsCallable('createStreamUserAndGetToken'); - final results = await callable(); - print('Stream account created, token: ${results.data}'); -} -``` - -Calling this method will do the following: -1. Create a new Firebase User and authenticate that user. -2. Call the `createStreamUserAndGetToken` cloud function and get the Stream user token for the authenticated user. - -As you can see, calling a cloud function is easy and will also send all the necessary user authentication information (such as the UID) -in the request. - -Once you have the Stream user token, you can authenticate your Stream Chat user as you normally would. - -Please see our [initialization documentation](https://getstream.io/chat/docs/flutter-dart/init_and_users/?language=dart) for more information. - -As you can see below, the User ID matches on both Firebase's and Stream's user database. - -##### Firebase Authentication Database - -![Firebase Auth Database with new user created](../assets/firebase_authentication_dashboard.jpg) - -##### Stream Chat User Database - -![Stream chat user database new account created](../assets/stream_chat_user_database.jpg) - - -### Get the Stream User Token - -The `getStreamUserToken` cloud function is very similar to the `createStreamUserAndGetToken` function. The only difference is -that it only creates a user token and does not create a new user account on Stream. - -Update the **`signIn`** method in your Flutter code to the following: - -```dart -Future signIn() async { - // Sign in with Firebase - await auth.signInWithEmailAndPassword(email: email, password: password); - print('Firebase signed in'); - - // Get Stream user token - final callable = functions.httpsCallable('getStreamUserToken'); - final results = await callable(); - print('Stream user token retrieved: ${results.data}'); -} -``` - -Calling this method will do the following: -1. Sign in using Firebase Auth. -2. Call the `getStreamUserToken` cloud function to get a Stream user token. - -:::note -The user needs to be authenticated to call this cloud function. Otherwise, the function will throw -the **failed-precondition** error that you specified. -::: - -### Revoke Stream User Token - -You may also want to revoke the Stream user token if you sign out from Firebase. - -Update the `signOut` method in your Flutter code to the following: - -```dart -Future signOut() async { - // Revoke Stream user token. - final callable = functions.httpsCallable('revokeStreamUserToken'); - await callable(); - print('Stream user token revoked'); - - // Sign out Firebase. - await auth.signOut(); - print('Firebase signed out'); -} -``` -:::note -Call the cloud function before signing out from Firebase. -::: - -### Delete Stream User - -When deleting a Firebase user account, it would make sense also to delete the -associated Stream user account. - -The cloud function looks like this: - -```js -// When a user is deleted from Firebase their associated Stream account is also deleted. -exports.deleteStreamUser = functions.auth.user().onDelete((user, context) => { - return serverClient.deleteUser(user.uid); -}); -``` - -In this function, you are listening to delete events on Firebase auth. When an account is deleted, this function will be triggered, and you can get the -user's **`uid`** and call the `deleteUser` method on the `serverClient`. - -This is not an external cloud function; it can only be triggered when an -account is deleted. - -### Conclusion - -In this guide, you have seen how to securely create Stream Chat tokens using -Firebase Authentication and Cloud Functions. - -The principles shown in this guide can be applied to your preferred authentication -provider and cloud architecture of choice. \ No newline at end of file diff --git a/docusaurus/docs/Flutter/05-guides/04-adding_localization.mdx b/docusaurus/docs/Flutter/05-guides/04-adding_localization.mdx deleted file mode 100644 index 4f9456930e..0000000000 --- a/docusaurus/docs/Flutter/05-guides/04-adding_localization.mdx +++ /dev/null @@ -1,203 +0,0 @@ ---- -id: adding_localization -title: Localization ---- - -Adding Localization (l10n) / Internationalization (i18n) To UI Widgets - -### Introduction - -We have a dedicated package for adding localization to our UI widgets. It's called `stream_chat_localizations` and you can find it [here](https://pub.dev/packages/stream_chat_localizations). - -![](../assets/localization_support.jpg) - -## What is Localization? - -If you deploy your app to users who speak another language, you'll need to internationalize (localize) it. That means you need to write the app in a way that makes it possible to localize values like text and layouts for each language or locale that the app supports. For more information, see the [Flutter documentation](https://flutter.dev/docs/development/accessibility-and-localization/internationalization). - -What this package allows you to do is to provide localized strings for the Stream chat widgets. For example, depending on the application locale, the Stream Chat widgets will display the appropriate language. The locale will be set automatically, based on system preferences, or you could set it programmatically in your app. The package supports several different languages, with more to be added. The package allows you to override any supported language or add a new language that isn't supported. - -:::note -If you want to translate messages, or enable automatic translation, please see the [Translation documentation](https://getstream.io/chat/docs/flutter-dart/translation/?language=dart). -::: - -### Supported languages - -At the moment we support the following languages: -- [English](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart) -- [Hindi](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart) -- [Italian](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart) -- [French](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart) -- [Spanish](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart) -- [Japanese](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart) -- [Korean](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart) -- [Portuguese](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_pt.dart) -- [German](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_de.dart) -- [Norwegian](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_no.dart) -More languages will be added in the future. Feel free to [contribute](https://github.com/GetStream/stream-chat-flutter/blob/master/CONTRIBUTING.md) to add more languages. - -### Add dependency - -Add this to your package's `pubspec.yaml` file, use the latest version [![Pub](https://img.shields.io/pub/v/stream_chat_localizations.svg)](https://pub.dartlang.org/packages/stream_chat_localizations) -```yaml -dependencies: - stream_chat_localizations: ^latest_version -``` - -Then run `flutter packages get` - -### Usage - -Generally, Flutter and the Stream Chat SDK will use the system locale of the user's device, if that locale is supported (see below). If the locale is not supported we will default to `en` (however it's always possible to [customize that](#changing-the-default-language)). -Make sure to read more about localization in the [official Flutter docs](https://flutter.dev/docs/development/accessibility-and-localization/internationalization). - -```dart -import 'package:flutter/material.dart'; -import 'package:stream_chat_localizations/stream_chat_localizations.dart'; - -void main() { - WidgetsFlutterBinding.ensureInitialized(); - runApp(MyApp()); -} - -class MyApp extends StatelessWidget { - - // Setup client and channel code here - ... - - @override - Widget build(BuildContext context) { - return MaterialApp( - // Add all the supported locales - supportedLocales: const [ - Locale('en'), - Locale('hi'), - Locale('fr'), - Locale('it'), - Locale('es'), - Locale('ja'), - Locale('ko'), - Locale('pt'), - Locale('de'), - Locale('no'), - ], - // Add GlobalStreamChatLocalizations.delegates - localizationsDelegates: GlobalStreamChatLocalizations.delegates, - builder: (context, widget) => StreamChat( - client: client, - child: widget, - ), - home: StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ); - } -} -``` - -## Setting a language -The application language can be changed through system preferences or programmatically. - -### System Preferences -The application locale can be changed by changing the language for your device or emulator within the device's system preferences. - -[iOS change language](https://support.apple.com/en-us/HT204031) - -[Android change language](https://support.google.com/websearch/answer/3333234?co=GENIE.Platform%3DAndroid&hl=en) - -Note that the language needs to be supported in your application to work. - -### Programmatically -You can also set the locale programmatically in your Flutter application without changing the device's language. - -```dart -return MaterialApp( - ... - locale: const Locale('fr'), - ... -); -``` - -There are many ways that this can be set for additional control. For information and examples, see this [Stack Overflow post](https://stackoverflow.com/questions/49441212/flutter-multi-lingual-application-how-to-override-the-locale). - -### Adding a new language - -To add a new language, create a new class extending `GlobalStreamChatLocalizations` and create a delegate for it, adding it to the `delegates` array. - -Check out [this example](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/example/lib/add_new_lang.dart) to see how to add a new language. - -### Override existing languages - -To override an existing language, create a new class extending that particular language class and create a delegate for it, adding it to the `delegates` array. - -Check out [this example](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/example/lib/override_lang.dart) to see how to override an existing language. - -### Changing the default language - -To change the default language you can use the `MaterialApp.localeListResolutionCallback` property. -Here is an example of how that would look like: - -```dart - MaterialApp( - theme: ThemeData.light(), - darkTheme: ThemeData.dark(), - // Add all the supported locales - supportedLocales: const [ - Locale('en'), - Locale('hi'), - Locale('fr'), - Locale('it'), - Locale('es'), - Locale('ja'), - Locale('ko'), - ], - // locales are the locales of the device - // supportedLocales are the app supported locales - localeListResolutionCallback: (locales, supportedLocales) { - // We map the supported locales to language codes - // note that this is completely optional and this logic can be changed as you like - final supportedLanguageCodes = - supportedLocales.map((e) => e.languageCode); - if (locales != null) { - // we iterate over the locales and find the first one that is supported - for (final locale in locales) { - if (supportedLanguageCodes.contains(locale.languageCode)) { - return locale; - } - } - } - - // if we didn't find a supported language, we return the Italian language - return const Locale('it'); - }, - // Add GlobalStreamChatLocalizations.delegates - localizationsDelegates: GlobalStreamChatLocalizations.delegates, - ... - -``` - -In this case, we're using Italian as the default language. - -### ⚠️ Note on **iOS** - -For translation to work on **iOS** you need to add supported locales to -`ios/Runner/Info.plist` as described [here](https://flutter.dev/docs/development/accessibility-and-localization/internationalization#specifying-supportedlocales). - -Example: - -```xml -CFBundleLocalizations - - en - hi - fr - it - es - ja - ko - pt - de - no - -``` diff --git a/docusaurus/docs/Flutter/05-guides/05-push-notifications/_category_.json b/docusaurus/docs/Flutter/05-guides/05-push-notifications/_category_.json deleted file mode 100644 index 26b1d64ec7..0000000000 --- a/docusaurus/docs/Flutter/05-guides/05-push-notifications/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Push Notifications" -} \ No newline at end of file diff --git a/docusaurus/docs/Flutter/05-guides/05-push-notifications/adding_push_notifications.mdx b/docusaurus/docs/Flutter/05-guides/05-push-notifications/adding_push_notifications.mdx deleted file mode 100644 index 6859251ed3..0000000000 --- a/docusaurus/docs/Flutter/05-guides/05-push-notifications/adding_push_notifications.mdx +++ /dev/null @@ -1,262 +0,0 @@ ---- -id: adding_push_notifications -title: Legacy ---- - -Adding Push Notifications To Your Application - -:::note -Version 1 (legacy) of push notifications won't be removed immediately but there won't be any new features. That's why new applications are highly recommended to use version 2 from the beginning to leverage upcoming new features. -::: - -### Introduction - -Push notifications are a core part of the experience for a messaging app. Users often need to be notified -of new messages and old notifications sometimes need to be updated silently as well. - -This guide details how to add push notifications to your app. - -Make sure to check [this section](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart) of the docs to read about the push delivery logic. - -### Setup FCM - -To integrate push notifications in your Flutter app you need to use the package [`firebase_messaging`](https://pub.dev/packages/firebase_messaging). - - -Follow the [Firebase documentation](https://firebase.flutter.dev/docs/messaging/overview/) to know how to set up the plugin for both Android and iOS. - - -Once that's done FCM should be able to send push notifications to your devices. - -### Integration with Stream - -#### Step 1 - -From the [Firebase Console](https://console.firebase.google.com/), select the project your app belongs to. - -#### Step 2 - -Click on the gear icon next to `Project Overview` and navigate to **Project settings** - -![](../../assets/firebase_project_settings.jpeg) - -#### Step 3 - -Navigate to the `Cloud Messaging` tab - -#### Step 4 - -Under `Project Credentials`, locate the `Server key` and copy it - -![](../../assets/server_key.png) - -#### Step 5 - -Upload the `Server Key` in your chat dashboard - -![](../../assets/dashboard_firebase_enable.jpeg) - -![](../../assets/dashboard_firebase_key.jpeg) - - -:::note -We are setting up the Android section, but this will work for both Android and iOS if you're using Firebase for both of them. -::: - -#### Step 6 - -Save your push notification settings changes - -![](../../assets/dashboard_save_changes.jpeg) - -**OR** - -Upload the `Server Key` via API call using a backend SDK - -```js -await client.updateAppSettings({ - firebase_config: { - server_key: 'server_key', - notification_template: `{"message":{"notification":{"title":"New messages","body":"You have {{ unread_count }} new message(s) from {{ sender.name }}"},"android":{"ttl":"86400s","notification":{"click_action":"OPEN_ACTIVITY_1"}}}}`, - data_template: `{"sender":"{{ sender.id }}","channel":{"type": "{{ channel.type }}","id":"{{ channel.id }}"},"message":"{{ message.id }}"}` - }, -}); -``` - -### Registering a device at Stream Backend - -Once you configure Firebase server key and set it up on Stream dashboard a device that is supposed to receive push notifications needs to be registered at Stream backend. This is usually done by listening for Firebase device token updates and passing them to the backend as follows: - -```dart -firebaseMessaging.onTokenRefresh.listen((token) { - client.addDevice(token, PushProvider.firebase); -}); -``` - -### Possible issues - - -We only send push notifications when the user doesn't have any active web socket connection (which is established when you call `client.connectUser`). If you set the [onBackgroundEventReceived](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/onBackgroundEventReceived.html) property of the StreamChat widget, when your app goes to background, your device will keep the WS connection alive for 1 minute, and so within this period, you won't receive any push notification. - -Make sure to read the [general push docs](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart) in order to avoid known gotchas that may make your relationship with notifications go bad 😢 - -### Testing if Push Notifications are Setup Correctly - -If you're not sure if you've set up push notifications correctly (for example you don't always receive them, they work unreliably), you can follow these steps to make sure your configuration is correct and working: - -1. Clone our repository for push testing git clone git@github.com:GetStream/chat-push-test.git - -2. `cd flutter` - -3. In folder run `flutter pub get` - -4. Input your API key and secret in `lib/main.dart` - -5. Change the bundle identifier/application ID and development team/user so you can run the app in your device (**do not** run on iOS simulator, Android emulator is fine) - -6. Add your `google-services.json/GoogleService-Info.plist` - -7. Run the app - -8. Accept push notification permission (iOS only) - -9. Tap on `Device ID` and copy it - -10. Send the app to background - -11. After configuring [stream-cli](https://github.com/GetStream/stream-cli) paste the following command on command line using your user ID - -```shell -stream chat:push:test -u -``` - -You should get a test push notification - -### App in the background but still connected - -The [StreamChat](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat-class.html) widget lets you define a [onBackgroundEventReceived](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/onBackgroundEventReceived.html) handler in order to handle events while the app is in the background, but the client is still connected. - -This is useful because it lets you keep the connection alive in cases in which the app goes in the background just for some seconds (for example multitasking, picking pictures from the gallery...) - -You can even customize the [backgroundKeepAlive](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/backgroundKeepAlive.html) duration. - -In order to show notifications in such a case we suggest using the package [`flutter_local_notifications`](https://pub.dev/packages/flutter_local_notifications); follow the package guide to successfully set up the plugin. - -Once that's done you should set the [onBackgroundEventReceived](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/onBackgroundEventReceived.html); here is an example: - -```dart -... -StreamChat( - client: client, - onBackgroundEventReceived: (e) { - final currentUserId = client.state.user.id; - if (![ - EventType.messageNew, - EventType.notificationMessageNew, - ].contains(event.type) || - event.user.id == currentUserId) { - return; - } - if (event.message == null) return; - final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); - final initializationSettingsAndroid = - AndroidInitializationSettings('launch_background'); - final initializationSettingsIOS = IOSInitializationSettings(); - final initializationSettings = InitializationSettings( - android: initializationSettingsAndroid, - iOS: initializationSettingsIOS, - ); - await flutterLocalNotificationsPlugin.initialize(initializationSettings); - await flutterLocalNotificationsPlugin.show( - event.message.id.hashCode, - event.message.user.name, - event.message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'message channel', - 'Message channel', - 'Channel used for showing messages', - priority: Priority.high, - importance: Importance.high, - ), - iOS: IOSNotificationDetails(), - ), - ); - }, - child: .... -); -... -``` - -As you can see we generate a local notification whenever a message.new or notification.message_new event is received. - -### Foreground notifications - -Sometimes you may want to show a notification when the app is in the foreground. -For example, when you're in a channel and you receive a new message from someone in another channel. - -For this scenario, you can also use the `flutter_local_notifications` package to show a notification. - -You need to listen for new events using `StreamChatClient.on` and handle them accordingly. - -Here we're checking if the event is a `message.new` or `notification.message_new` event, and if the message is from a different user than the current user. In that case we'll show a notification. - -```dart -client.on( - EventType.messageNew, - EventType.notificationMessageNew, -).listen((event) { - if (event.message?.user?.id == client.state.currentUser?.id) { - return; - } - showLocalNotification(event, client.state.currentUser!.id, context); -}); -``` - -:::note -You should also check that the channel of the message is different than the channel in the foreground. -How you do this depends on your app infrastructure and how you handle navigation. -Take a look at the [Stream Chat v1 sample app](https://github.com/GetStream/flutter-samples/blob/main/packages/stream_chat_v1/lib/home_page.dart#L11) to see how we're doing it over there. -::: - -### Saving notification messages to the offline storage - -You may want to save received messages when you receive them via a notification so that later on when you open the app they're already there. - -To do this we need to update the push notification data payload at Stream Dashboard and clear the notification one: - -```json -{ - "message_id": "{{ message.id }}", - "channel_id": "{{ channel.id }}", - "channel_type": "{{ channel.type }}" -} -``` - -Then we need to integrate the package [`stream_chat_persistence`](https://pub.dev/packages/stream_chat_persistence) in our app that exports a persistence client, learn [here](https://pub.dev/packages/stream_chat_persistence#usage) how to set it up. - -Then during the call `firebaseMessaging.configure(...)` we need to set the `onBackgroundMessage` parameter using a TOP-LEVEL or STATIC function to handle background messages; here is an example: - -```dart -Future myBackgroundMessageHandler(message) async { - if (message.containsKey('data')) { - final data = message['data']; - final messageId = data['message_id']; - final channelId = data['channel_id']; - final channelType = data['channel_type']; - final cid = '$channelType:$channelId'; - - final client = StreamChatClient(apiKey); - final persistenceClient = StreamChatPersistenceClient(); - await persistenceClient.connect(userId); - - final message = await client.getMessage(messageId).then((res) => res.message); - - await persistenceClient.updateMessages(cid, [message]); - persistenceClient.disconnect(); - - /// This can be done using the package flutter_local_notifications as we did before 👆 - _showLocalNotification(); - } -} -``` diff --git a/docusaurus/docs/Flutter/05-guides/05-push-notifications/adding_push_notifications_v2.mdx b/docusaurus/docs/Flutter/05-guides/05-push-notifications/adding_push_notifications_v2.mdx deleted file mode 100644 index 81ee284ad5..0000000000 --- a/docusaurus/docs/Flutter/05-guides/05-push-notifications/adding_push_notifications_v2.mdx +++ /dev/null @@ -1,355 +0,0 @@ ---- -id: adding_push_notifications_v2 -title: Push Notifications ---- - -Adding Push Notifications (V2) To Your Application - -### Introduction - -This guide details how to add push notifications to your app. - -Push notifications are a core part of the experience for a messaging app. Users often need to be notified -of new messages and old notifications sometimes need to be updated silently. - -Stream Chat sends push notification to channel members that have at least one registered device. -Push notifications are only sent for new messages and not for other events. -You can use [Webhooks](https://getstream.io/chat/docs/android/webhooks_overview/) to send push notifications on other types of events. - -You can read more about Stream’s [push delivery logic](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart#push-delivery-rules). - -To receive push notifications from Stream Chat, 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). - -### Push Delivery Rules - -Push message delivery behaves according to these rules: - -- Push notifications are sent only for new messages. -- Only channel members receive push messages. -- Members receive push notifications regardless of their online status. -- Replies inside a [thread](https://getstream.io/chat/docs/threads/) are only sent to users that are part of that thread: - - They posted at least one message - - They were mentioned -- Messages from muted users are not sent. -- Messages from muted channels are not sent. -- Messages are sent to all registered devices for a user (up to 25). -- The message doesn't contain the flag `skip_push` as true. -- `push_notifications` is enabled (default) on the channel type for message is sent. - -:::caution - -Push notifications require membership. Watching a channel isn't enough. - -::: - -### Setup FCM - -To integrate push notifications in your Flutter app, you need to use the package [`firebase_messaging`](https://pub.dev/packages/firebase_messaging). - -Follow the [Flutter Firebase documentation](https://firebase.flutter.dev/docs/messaging/overview/) to set up the plugin for Android and iOS. -Additional setup and instructions can be found [here](https://firebase.google.com/docs/cloud-messaging/flutter/client). Be sure to read this documentation to understand Firebase messaging functionality. - -Once that's done, FCM should be able to send push notifications to your devices. - -### Integration With Stream - -#### Step 1 - Get the Firebase Credentials - -These credentials are the [private key file](https://firebase.google.com/docs/admin/setup#:~:text=To%20generate%20a%20private%20key%20file%20for%20your%20service%20account%3A) 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 can upload your Firebase credentials using either the dashboard or the app settings API (available only in backend SDKs). - -##### Using the Stream Dashboard - -1. Go to the **Chat Overview** page on Stream Dashboard. - -![](../../assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png) - -2. Enable **Firebase Notification** toggle on **Chat Overview**. - -![](../../assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png) - -3. Enter your Firebase Credentials and press `"Save"`. - -##### Using the API - -You can also enable Firebase notifications and upload the Firebase credentials using one of our server SDKs. - -For example, using the Stream JavaScript SDK: - -```js -const client = StreamChat.getInstance('api_key', 'api_secret'); -client.updateAppSettings({ - push_config: { - version: 'v2' - }, - firebase_config: { - credentials_json: fs.readFileSync( - './firebase-credentials.json', - 'utf-8', - ), - }); -``` - -### Registering a Device With Stream Backend - -Once you configure a Firebase server key 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. This is usually done by listening for Firebase device token updates and passing them to the backend as follows: - -```dart -firebaseMessaging.onTokenRefresh.listen((token) { - client.addDevice(token, PushProvider.firebase); -}); -``` - -Push Notifications v2 also supports specifying a name for the push device tokens you register. By setting the optional `pushProviderName` parameter in the `addDevice` call, you can support different configurations between the device and the `PushProvider`. - -```dart -firebaseMessaging.onTokenRefresh.listen((token) { - client.addDevice(token, PushProvider.firebase, pushProviderName: 'my-custom-config'); -}); -``` - -### Receiving Notifications - -Push notifications behave differently depending on whether you are using iOS or Android. -See [here](https://firebase.flutter.dev/docs/messaging/usage#message-types) to understand the difference between **notification** and **data** payloads. - -#### iOS - -On iOS, we send both a **notification** and a **data** payload. -This means you don't need to do anything special to get the notification to show up. However, you might want to handle the data payload to perform some logic when the user taps on the notification. - -To update the template, you can use a backend SDK. -For example, using the Stream JavaScript SDK: - -```js -const client = StreamChat.getInstance(‘api_key’, ‘api_secret’); -const apn_template = `{ - "aps": { - "alert": { - "title": "New message from {{ sender.name }}", - "body": "{{ truncate message.text 2000 }}" - }, - "mutable-content": 1, - "category": "stream.chat" - }, - "stream": { - "sender": "stream.chat", - "type": "message.new", - "version": "v2", - "id": "{{ message.id }}", - "cid": "{{ channel.cid }}" - } -}`; - -client.updateAppSettings({ - firebase_config: { - apn_template, - }); -``` - -#### Android - -On Android, we send only a **data** payload. This gives you more flexibility and lets you decide what to do with the notification. - -For example, you can listen and generate a notification from them. - -The code below demonstrates how to generate a notification when a **data-only** message is received and the app is in the background. - -There are a few things to keep in mind about your background message handler: - -1. It must not be an anonymous function. -2. It must be a top-level function (not a class method which requires initialization). -3. It must be annotated with @pragma('vm:entry-point') right above the function declaration (otherwise it may be removed during tree shaking for release mode). - -For additional information on background messages, please see the [Firebase documentation](https://firebase.google.com/docs/cloud-messaging/flutter/receive#background_messages). - -```dart -@pragma('vm:entry-point') -Future onBackgroundMessage(RemoteMessage message) async { - final chatClient = StreamChatClient(apiKey); - - chatClient.connectUser( - User(id: userId), - userToken, - connectWebSocket: false, - ); - - handleNotification(message, chatClient); -} - -void handleNotification( - RemoteMessage message, - StreamChatClient chatClient, -) async { - - final data = message.data; - - if (data['type'] == 'message.new') { - final flutterLocalNotificationsPlugin = await setupLocalNotifications(); - final messageId = data['id']; - final response = await chatClient.getMessage(messageId); - - flutterLocalNotificationsPlugin.show( - 1, - 'New message from ${response.message.user!.name} in ${response.channel!.name}', - response.message.text, - const NotificationDetails( - android: AndroidNotificationDetails( - 'new_message', - 'New message notifications channel', - )), - ); - } -} - -FirebaseMessaging.onBackgroundMessage(onBackgroundMessage); -``` - -In the above example, you get the message details using the `getMessage` method, and then you use the [`flutter_local_notifications`](https://pub.dev/packages/flutter_local_notifications) package to show the actual notification. - -##### Using a Template on Android - -Adding a **notification** payload to Android notifications is still possible. -You can do so by adding a template using a backend SDK. -For example, using the Stream JavaScript SDK: - -```js -const client = StreamChat.getInstance(‘api_key’, ‘api_secret’); -const notification_template = ` -{ - "title": "{{ sender.name }} @ {{ channel.name }}", - "body": "{{ message.text }}", - "click_action": "OPEN_ACTIVITY_1", - "sound": "default" -}`; - -client.updateAppSettings({ - firebase_config: { - notification_template, - }); -``` - -### Possible Issues - -Make sure to read the [general push notification docs](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart) to prevent common issues with notifications 😢. - -### Testing if Push Notifications are Setup Correctly - -If you're not sure whether you've set up push notifications correctly, for example, you don't always receive them, or they don’t work reliably, then you can follow these steps to make sure your configuration is correct and working: - -1. Clone our repository for push testing: `git clone git@github.com:GetStream/chat-push-test.git` -2. `cd chat-push-test/flutter` -3. In that folder run `flutter pub get` -4. Input your API key and secret in `lib/main.dart` -5. Change the bundle identifier/application ID and development team/user so you can run the app on your physical device.**Do not** run on an iOS simulator, as it will not work. Testing on an Android emulator is fine. -6. Add your `google-services.json/GoogleService-Info.plist` -7. Run the app -8. Accept push notification permission (iOS only) -9. Tap on `Device ID` and copy it -10. After configuring [stream-cli](https://github.com/GetStream/stream-cli), run the following command using your user ID: - -```shell -stream chat:push:test -u -``` - -You should get a test push notification 🥳 - -### Foreground Notifications - -You may want to show a notification when the app is in the foreground. -For example, when you're in a channel and receive a new message from someone in another channel. - -For this scenario, you can also use the `flutter_local_notifications` package to show a notification. - -You need to listen for new events using `FirebaseMessaging.onMessage.listen()` and handle them accordingly: - -```dart -FirebaseMessaging.onMessage.listen((message) async { - handleNotification( - message, - chatClient, - ); -}); -``` - -:::note -You should also check that the message's channel differs from the channel in the foreground. -How you do this depends on your app infrastructure and how you handle navigation. - -Take a look at the [Stream Chat v1 sample app](https://github.com/GetStream/flutter-samples/blob/main/packages/stream_chat_v1/lib/home_page.dart#L11) to see how we're doing it over there. -::: - -### Saving Notification Messages to the Offline Storage (Only Android) - -When the app is closed, you can save incoming messages when you receive them via a notification so that they're already there later when you open the app. - -To do this, you need to integrate the package [`stream_chat_persistence`](https://pub.dev/packages/stream_chat_persistence) that exports a persistence client. See [here](https://pub.dev/packages/stream_chat_persistence#usage) for information on how to set it up. - -Then calling `FirebaseMessaging.onBackgroundMessage(...)` you need to use a TOP-LEVEL or STATIC function to handle background messages. - -For additional information on background messages, please see the [Firebase documentation](https://firebase.google.com/docs/cloud-messaging/flutter/receive#background_messages). - -Here is an example: - -```dart -@pragma('vm:entry-point') -Future onBackgroundMessage(RemoteMessage message) async { - final chatClient = StreamChatClient(apiKey); - final persistenceClient = StreamChatPersistenceClient(); - - await persistenceClient.connect(userId); - - chatClient.connectUser( - User(id: userId), - userToken, - connectWebSocket: false, - ); - - handleNotification(message, chatClient); -} - -void handleNotification( - RemoteMessage message, - StreamChatClient chatClient, -) async { - final data = message.data; - if (data['type'] == 'message.new') { - final flutterLocalNotificationsPlugin = await setupLocalNotifications(); - final messageId = data['id']; - final cid = data['cid']; - final response = await chatClient.getMessage(messageId); - await persistenceClient.updateMessages(cid, [response.message]); - - persistenceClient.disconnect(); - - flutterLocalNotificationsPlugin.show( - 1, - 'New message from ${response.message.user.name} in ${response.channel.name}', - response.message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'new_message', - 'New message notifications channel', - )), - ); - } -} - -FirebaseMessaging.onBackgroundMessage(onBackgroundMessage); -``` diff --git a/docusaurus/docs/Flutter/05-guides/06-end_to_end_chat_encryption.mdx b/docusaurus/docs/Flutter/05-guides/06-end_to_end_chat_encryption.mdx deleted file mode 100644 index cf204cfc60..0000000000 --- a/docusaurus/docs/Flutter/05-guides/06-end_to_end_chat_encryption.mdx +++ /dev/null @@ -1,259 +0,0 @@ ---- -id: end_to_end_chat_encryption -title: Encryption ---- - -Adding End To End Encryption to your Chat App - -## Introduction - -When you communicate over a chat application with another person or group, -you may exchange sensitive information, like personally identifiable information, financial details, or passwords. -A chat application should use end-to-end encryption to ensure that users' data stays secure. - -:::note -Before you start, keep in mind that this guide is a basic example intended for educational purposes only. -If you want to implement end-to-end encryption in your production app, please consult a security professional first. -There’s a lot more to consider from a security perspective that isn’t covered here. -::: - -## What is End-to-End Encryption? - -End-to-end encryption (E2EE) is the process of securing a message from third parties so that only the sender and receiver can access the message. -E2EE provides security by storing the message in an encrypted form on the application's server or database. - -You can only access the message by decrypting and signing it using a known public key (distributed freely) -and a corresponding private key (only known by the owner). - -Each user in the application has their own public-private key pair. -Public keys are distributed publicly and encrypt the sender’s messages. -The receiver can only decrypt the sender’s message with the matching private key. - -Check out the diagram below for an example: - -![](../assets/end_to_end_encryption.png) - -## Setup - -### Dependencies - -Add the [`webcrypto`](https://pub.dev/packages/webcrypto) package in your `pubspec.yaml` file. - -```yaml -dependencies: - webcrypto: ^0.5.2 # latest version -``` - -### Generate Key Pair - -Write a function that generates a key pair using the **ECDH** algorithm and the **P-256** elliptic curve (**P-256** is well-supported and -offers the right balance of security and performance). - -The pair will consist of two keys: -- **PublicKey**: The key that is linked to a user to encrypt messages. -- **PrivateKey**: The key that is stored locally to decrypt messages. - -```dart -Future generateKeys() async { - final keyPair = await EcdhPrivateKey.generateKey(EllipticCurve.p256); - final publicKeyJwk = await keyPair.publicKey.exportJsonWebKey(); - final privateKeyJwk = await keyPair.privateKey.exportJsonWebKey(); - - return JsonWebKeyPair( - privateKey: json.encode(privateKeyJwk), - publicKey: json.encode(publicKeyJwk), - ); -} - -// Model class for storing keys -class JsonWebKeyPair { - const JsonWebKeyPair({ - required this.privateKey, - required this.publicKey, - }); - - final String privateKey; - final String publicKey; -} -``` - -### Generate a Cryptographic Key - -Next, create a symmetric **Cryptographic Key** using the keys generated in the previous step. -You will use those keys to encrypt and decrypt messages. - -```dart -// SendersJwk -> sender.privateKey -// ReceiverJwk -> receiver.publicKey -Future> deriveKey(String senderJwk, String receiverJwk) async { - // Sender's key - final senderPrivateKey = json.decode(senderJwk); - final senderEcdhKey = await EcdhPrivateKey.importJsonWebKey( - senderPrivateKey, - EllipticCurve.p256, - ); - - // Receiver's key - final receiverPublicKey = json.decode(receiverJwk); - final receiverEcdhKey = await EcdhPublicKey.importJsonWebKey( - receiverPublicKey, - EllipticCurve.p256, - ); - - // Generating CryptoKey - final derivedBits = await senderEcdhKey.deriveBits(256, receiverEcdhKey); - return derivedBits; -} -``` - -### Encrypting Messages - -Once you have generated the **Cryptographic Key**, you're ready to encrypt the message. -You can use the **AES-GCM** algorithm for its known security and performance balance and good browser availability. - -```dart -// The "iv" stands for initialization vector (IV). To ensure the encryption’s strength, -// each encryption process must use a random and distinct IV. -// It’s included in the message so that the decryption procedure can use it. -final Uint8List iv = Uint8List.fromList('Initialization Vector'.codeUnits); -``` - -```dart -Future encryptMessage(String message, List deriveKey) async { - // Importing cryptoKey - final aesGcmSecretKey = await AesGcmSecretKey.importRawKey(deriveKey); - - // Converting message into bytes - final messageBytes = Uint8List.fromList(message.codeUnits); - - // Encrypting the message - final encryptedMessageBytes = - await aesGcmSecretKey.encryptBytes(messageBytes, iv); - - // Converting encrypted message into String - final encryptedMessage = String.fromCharCodes(encryptedMessageBytes); - return encryptedMessage; -} -``` - -### Decrypting Messages - -Decrypting a message is the opposite of encrypting one. -To decrypt a message to a human-readable format, use the code snippet below: - -```dart -Future decryptMessage(String encryptedMessage, List deriveKey) async { - // Importing cryptoKey - final aesGcmSecretKey = await AesGcmSecretKey.importRawKey(deriveKey); - - // Converting message into bytes - final messageBytes = Uint8List.fromList(encryptedMessage.codeUnits); - - // Decrypting the message - final decryptedMessageBytes = - await aesGcmSecretKey.decryptBytes(messageBytes, iv); - - // Converting decrypted message into String - final decryptedMessage = String.fromCharCodes(decryptedMessageBytes); - return decryptedMessage; -} -``` - -## Implement as a Stream Chat Feature - -Now that your setup is complete you can use it to implement end-to-end encryption in your app. - -### Store User's Public Key - -The first thing you need to do is store the generated `publicKey` as an `extraData` property, in order -for other users to encrypt messages. - -```dart -// Generating keyPair using the function defined in above steps -final keyPair = generateKeys(); -``` - -```dart -await client.connectUser( - User( - id: 'cool-shadow-7', - name: 'Cool Shadow', - image: 'https://getstream.io/cool-shadow', - - // set publicKey as a extraData property - extraData: { 'publicKey': keyPair.publicKey }, - ), - client.devToken('cool-shadow-7').rawValue, -); -``` - -### Sending Encrypted Messages - -Now you will use the `encryptMessage()` function created in the previous steps to encrypt the message. - -To do that, you need to make some minor changes to the **StreamMessageInput** widget. - -```dart -final receiverJwk = receiver.extraData['publicKey']; - -// Generating derivedKey using user's privateKey and receiver's publicKey -final derivedKey = await deriveKey(keyPair.privateKey, receiverJwk); -``` - -```dart -StreamMessageInput( - - ... - - preMessageSending: (message) async { - // Encrypting the message text using derivedKey - final encryptedMessage = await encryptMessage(message.text, derivedKey); - - // Creating a new message with the encrypted message text - final newMessage = message.copyWith(text: encryptedMessage); - - return newMessage; - }, -), -``` - -`preMessageSending` is a parameter that allows your app to process the message before it goes to Stream’s server. -Here, you have used it to encrypt the message before sending it to Stream’s backend. - -### Showing Decrypted Messages - -Now, it’s time to decrypt the message and present it in a human-readable format to the receiver. - -You can customize the **StreamMessageListView** widget to have a custom `messagebuilder`, that can decrypt the message. - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, currentMessages, defaultWidget) { - // Retrieving the message from details - final message = messageDetails.message; - - // Decrypting the message text using the derivedKey - final decryptedMessageFuture = decryptMessage(message.text, derivedKey); - return FutureBuilder( - future: decryptedMessageFuture, - builder: (context, snapshot) { - if (snapshot.hasError) return Text('Error: ${snapshot.error}'); - if (!snapshot.hasData) return Container(); - - // Updating the original message with the decrypted text - final decryptedMessage = message.copyWith(text: snapshot.data); - - // Returning defaultWidget with updated message - return defaultWidget.copyWith( - message: decryptedMessage, - ); - }, - ); - }, -), -``` - -That's it. That's all you need to implement E2EE in a Stream powered chat app. - -For more details, check out our [end-to-end encrypted chat article](https://getstream.io/blog/end-to-end-encrypted-chat-in-flutter/#whats-end-to-end-encryption). diff --git a/docusaurus/docs/Flutter/05-guides/07-error_reporting_with_sentry.mdx b/docusaurus/docs/Flutter/05-guides/07-error_reporting_with_sentry.mdx deleted file mode 100644 index dbbe312e80..0000000000 --- a/docusaurus/docs/Flutter/05-guides/07-error_reporting_with_sentry.mdx +++ /dev/null @@ -1,143 +0,0 @@ ---- -id: error_reporting_with_sentry -title: Error Reporting ---- - -Error Reporting With Sentry - -## Introduction - -While one always tries to create apps that are free of bugs, they're sure to crop up from time to time. Since buggy apps lead to unhappy users and customers, it's important to understand how often your users experience bugs and where those bugs occur. That way, you can prioritize the bugs with the highest impact and work to fix them. - -Whenever an error occurs, create a report containing the error that occurred and the associated stack trace. You can then send the report to an error tracking service, such as [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), or [Firebase Crashlytics](https://firebase.google.com/docs/crashlytics). - -The error tracking service aggregates all of the crashes your users experience and groups them together. This allows you to know how often your app fails and where your users run into trouble. - -In this guide, learn how to report Stream Chat errors to the [Sentry](https://sentry.io/welcome/) crash reporting service using the following steps. - -### 1. Get a DSN From Sentry - -Before reporting errors to Sentry, you need a “DSN” to uniquely identify your app with the Sentry service: -To get a DSN, use the following steps: - -- [Create an account with Sentry](https://sentry.io/signup/). -- Log in to the account. -- Create a new Flutter project. -- Copy the code snippet that includes the DSN. - -### 2. Import the Sentry package - -Import the `sentry_flutter` package into your app. The sentry package makes it easier to send error reports to the Sentry error tracking service. - -```yaml -dependencies: - sentry_flutter: -``` - -### 3. Initialize the Sentry SDK - -Initialize the SDK to capture different unhandled errors automatically. - -```dart -import 'package:sentry_flutter/sentry_flutter.dart'; - -Future main() async { - await SentryFlutter.init( - (options) => options.dsn = 'https://example@sentry.io/example', - appRunner: () => runApp(const MyApp()), - ); -} -``` - -Or, if you want to run your app in your own error zone, use `runZonedGuarded`: - -```dart -void main() async { - /// Captures errors reported by the Flutter framework. - FlutterError.onError = (FlutterErrorDetails details) { - if (kDebugMode) { - // In development mode, simply print to console. - FlutterError.dumpErrorToConsole(details); - } else { - // In production mode, report to the application zone to report to Sentry. - Zone.current.handleUncaughtError(details.exception, details.stack!); - } - }; - - Future _reportError(dynamic error, StackTrace stackTrace) async { - // Print the exception to the console. - if (kDebugMode) { - // Print the full stack trace in debug mode. - print(stackTrace); - return; - } else { - // Send the Exception and Stacktrace to sentry in Production mode. - await Sentry.captureException(error, stackTrace: stackTrace); - } - } - - runZonedGuarded( - () async { - await SentryFlutter.init( - (options) => options.dsn = 'https://example@sentry.io/example', - ); - runApp(const MyApp()); - }, - _reportError, - ); -} -``` - -Alternatively, you can pass the DSN to Flutter using the **dart-define** tag: - -```bash ---dart-define SENTRY_DSN=https://example@sentry.io/example -``` - -### 4. Integration With StreamChat Applications - -Override the default `logHandlerFunction` to send errors to Sentry. - -```dart -void sampleAppLogHandler(LogRecord record) async { - if (kDebugMode) StreamChatClient.defaultLogHandler(record); - - // Report errors to Sentry - if (record.error != null || record.stackTrace != null) { - await Sentry.captureException( - record.error, - stackTrace: record.stackTrace, - ); - } -} - -StreamChatClient buildStreamChatClient( - String apiKey, { - Level logLevel = Level.SEVERE, -}) { - return StreamChatClient( - apiKey, - logLevel: logLevel, - logHandlerFunction: sampleAppLogHandler, // Pass the overridden logHandlerFunction - ); -} -``` - -### 5. Capture Errors Programmatically - -Besides the automatic error reporting that Sentry generates by importing and initializing the SDK, -you can use the API to manually report errors to Sentry: - -```dart -await Sentry.captureException(exception, stackTrace: stackTrace); -``` - -For more information, see the [Sentry API](https://pub.dev/documentation/sentry_flutter/latest/sentry_flutter/sentry_flutter-library.html) docs on Pub. - -### Complete Example - -To view a working example, see the [Stream Sample app](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). - -### Learn More - -Extensive documentation about using the Sentry SDK can be found on [Sentry's site](https://docs.sentry.io/platforms/flutter/). diff --git a/docusaurus/docs/Flutter/05-guides/08-adding_chat_to_video_livestreams.mdx b/docusaurus/docs/Flutter/05-guides/08-adding_chat_to_video_livestreams.mdx deleted file mode 100644 index 72f501208d..0000000000 --- a/docusaurus/docs/Flutter/05-guides/08-adding_chat_to_video_livestreams.mdx +++ /dev/null @@ -1,97 +0,0 @@ ---- -id: adding_chat_to_video_livestreams -title: Livestreams Integration ---- - -Adding Chat To Video Livestreams - -### Introduction - -Video livestreams are usually complemented with a chat section to make the livestream more interactive -and encourage retention. There are several ways to show the chat interface on the screen and requires -some design choices. - -This guide details multiple ways of adding chat functionality to your video livestream. - -### Implementing Chat - -There are two common scenarios in live-streaming applications depending how well integrated the two -components (video + chat) are allowed to be on the screen. Two common types are split-screen and a -chat overlay that fades in. - -Let's explore creating both types: - -### Split-screen - -In the split-screen implementation, we have a visual split between the video and the message list. -This allows the content to be unobstructed by chat and have a clear separation of boundaries. - -![](../assets/live_stream_1.jpg) - -```dart -Scaffold( - body: Column( - children: [ - Expanded( - child: // Your video implementation here, - ), - Expanded( - child: Column( - children: [ - Expanded( - child: StreamMessageListView(), - ), - StreamMessageInput(), - ], - ), - ), - ], - ), -) -``` - -### Overlapping chat with a transparency gradient - -Another way to add chat is to overlay the video content with messages which progressively fade out -as we go to the top of the screen. This gives the content a more rich feel as it takes the whole -screen and allows the chat to be more homogeneously integrated with the content. - -The second type looks like this: - -![](../assets/live_stream_2.jpg) - -We can use a `Stack` for achieving this: - -```dart -Stack( - children: [ - // Add your video implementation here - ShaderMask( - shaderCallback: (rect) { - return const LinearGradient( - begin: Alignment.bottomCenter, - end: Alignment.topCenter, - colors: [Colors.black, Colors.transparent], - stops: [0.4, 0.8]).createShader( - Rect.fromLTRB(0, 0, rect.width, rect.height), - ); - }, - blendMode: BlendMode.dstIn, - child: Column( - children: const [ - Expanded( - child: StreamMessageListViewTheme( - data: StreamMessageListViewThemeData( - backgroundColor: Colors.transparent, - ), - child: StreamMessageListView(), - ), - ), - StreamMessageInput(), - ], - ), - ), - ], -), -``` - diff --git a/docusaurus/docs/Flutter/05-guides/08-migrations/_category_.json b/docusaurus/docs/Flutter/05-guides/08-migrations/_category_.json deleted file mode 100644 index e30f7ae440..0000000000 --- a/docusaurus/docs/Flutter/05-guides/08-migrations/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Migrations" -} \ No newline at end of file diff --git a/docusaurus/docs/Flutter/05-guides/08-migrations/migration_guide_4_0.mdx b/docusaurus/docs/Flutter/05-guides/08-migrations/migration_guide_4_0.mdx deleted file mode 100644 index f2c830a71b..0000000000 --- a/docusaurus/docs/Flutter/05-guides/08-migrations/migration_guide_4_0.mdx +++ /dev/null @@ -1,753 +0,0 @@ ---- -id: migration_guide_4_0 -title: v4.0 -slug: /guides/migration_guide_4_0/ ---- - -**Version 4.0.0** of the Stream Chat Flutter SDK carries significant architectural changes to improve the developer experience by giving you more control and flexibility in how you use our core components and UI widgets. - -This v4.0 Migration Guide is intended to enumerate and better explain the changes in the SDK. - -If you find any bugs or have any questions, please file an [issue on our GitHub repository](https://github.com/GetStream/stream-chat-flutter/issues). We want to support you as much as we can with this migration. - -Code examples: - -- See our [Stream Chat Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) for an up-to-date guide using the latest Stream Chat version. -- See the [Stream Flutter Samples repository](https://github.com/GetStream/flutter-samples) with our full fledged messaging [sample application](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). - -All of our documentation has also been updated to support v4, so all of the guides and examples will have updated code. - -### Dependencies - -To migrate to v4.0.0, update your `pubspec.yaml` with the correct Stream chat package you're using: - -```yaml -dependencies: - stream_chat_flutter: ^4.0.0 # full UI, core and client packages - stream_chat_flutter_core: ^4.0.0 # core and client packages - stream_chat: ^4.0.0 # client package -``` - ---- - -## Name Changes - -The majority of the Stream Chat widgets and classes have now been renamed to have a “Stream” prefix associated with them. This increases Stream widgets' discoverability and avoids name conflicts when importing. - -For example, `MessageListView` is now called `StreamMessageListView`, and `UserAvatar` is renamed to `StreamUserAvatar`. - -**The old class names are deprecated and will be removed in the next major release (v5.0.0).** - -See the sections below on “deprecated classes” for a complete list of changes. Some of these classes/widgets have undergone functional changes as well, that will be explore in the following sections. - -## Removed Functionality/Widgets - -This section highlights functionality removed. - -### Removed Methods And Classes - -In version 4 we removed the following deprecated methods and classes: - -* `Channel.banUser` - -* `Channel.unbanUser` - -* `ClientState.user` - -* `ClientState.userStream` - -* `MessageWidget.allRead` - -* `MessageWidget.readList` - -* `StreamChat.user` - -* `StreamChat.userStream` - -* `StreamChatCore.user` - -* `StreamChatCore.userStream` - -These were marked as deprecated in v3. - -### Video Compression - -The automatic video compression when uploading a video has been removed. You can integrate this yourself by manipulating attachments using a [custom attachment uploader](https://getstream.io/chat/docs/flutter-dart/file_uploads/?language=dart). - -### Slidable Channel List Item - -The default slidable channel preview behavior has been removed. We have created a [guide](../../02-stream_chat_flutter/03-custom_widgets/07-slidable_channel_list_preview.mdx) showing you how you can easily add this functionality yourself. - -![Slidable demo](../../assets/slidable_demo.jpg) - -### Pin Permission - -`pinPermissions` is no longer needed in the **MessageListView** widget. The permissions are automatically fetched for each Stream project. To enable users to pin the message, make sure the pin permissions are granted for different types of users on your [Stream application dashboard](https://dashboard.getstream.io/). - ---- - -## Deprecated Classes - -This section covers all the deprecated classes and widgets in the Stream chat packages. Some of these have also undergone functional changes, for example, **MessageInput** and **ChannelsBloc**. These are discussed in more detail below. - -The majority of the Stream widgets and classes have now been renamed to have a **"Stream"** prefix associated with them. - -Changes: - -- `AttachmentTitle` in favor of `StreamAttachmentTitle` -- `AttachmentUploadStateBuilder` in favor of `StreamAttachmentsUploadStateBuilder` -- `AttachmentWidget` in favor of `StreamAttachmentWidget` -- `AvatarThemeData` in favor of `StreamAvatarThemeData` -- `ChannelAvatar` in favor of `StreamChannelAvatar` -- `ChannelBottomSheet` in favor of `StreamChannelInfoBottomSheet` -- `ChannelHeader` in favor of `StreamChannelHeader` -- `ChannelHeaderTheme` in favor of `StreamChannelHeaderTheme` -- `ChannelHeaderThemeData` in favor of `StreamChannelHeaderThemeData` -- `ChannelInfo` in favor of `StreamChannelInfo` -- `ChannelListHeader` in favor of `StreamChannelListHeader` -- `ChannelListHeaderTheme` in favor of `StreamChannelListHeaderTheme` -- `ChannelListHeaderThemeData` in favor of `StreamChannelListHeaderThemeData` -- `ChannelListView` in favor of `StreamChannelListView` -- `ChannelListViewTheme` in favor of `StreamChannelListViewTheme` -- `ChannelListViewThemeData` in favor of `StreamChannelListViewThemeData` -- `ChannelListHeader` in favor of `StreamChannelListHeader` -- `ChannelListView` in favor of `StreamChannelListView` -- `ChannelName` in favor of `StreamChannelName` -- `ChannelPreview` in favor of `StreamChannelListTile` -- `ChannelPreviewTheme` in favor of `StreamChannelPreviewTheme` -- `ChannelPreviewThemeData` in favor of `StreamChannelPreviewThemeData` -- `ChannelName` in favor of `StreamChannelName` -- `ColorTheme` in favor of `StreamColorTheme` -- `CommandsOverlay` in favor of `StreamCommandsOverlay` -- `ConnectionStatusBuilder` in favor of `StreamConnectionStatusBuilder` -- `DateDivider` in favor of `StreamDateDivider` -- `DeletedMessage` in favor of `StreamDeletedMessage` -- `EmojiOverlay` in favor of `StreamEmojiOverlay` -- `FileAttachment` in favor of `StreamFileAttachment` -- `FullScreenMedia` in favor of `StreamFullScreenMedia` -- `GalleryFooter` in favor of `StreamGalleryFooter` -- `GalleryFooterThemeData` in favor of `StreamGalleryFooterThemeData` -- `GalleryHeader` in favor of `StreamGalleryHeader` -- `GalleryHeaderTheme` in favor of `StreamGalleryHeaderTheme` -- `GalleryHeaderThemeData` in favor of `StreamGalleryHeaderThemeData` -- `GiphyAttachment` in favor of `StreamGiphyAttachment` -- `GradientAvatar` in favor of `StreamGradientAvatar` -- `GroupAvatar` in favor of `StreamGroupAvatar` -- `ImageAttachment` in favor of `StreamImageAttachment` -- `ImageGroup` in favor of `StreamImageGroup` -- `InfoTile` in favor of `StreamInfoTile` -- `MediaListView` in favor of `StreamMediaListView` -- `MessageAction` in favor of `StreamMessageAction` -- `MessageActionsModal` in favor `StreamMessageActionsModal` -- `MessageInput` in favor of `StreamMessageInput` -- `MessageInputTheme` in favor of `StreamMessageInputTheme` -- `MessageInputThemeData` in favor of `StreamMessageInputThemeData` -- `MessageInputState` in favor of `StreamMessageInput` -- `MessageListView` in favor of `StreamMessageListView` -- `MessageListViewTheme` in favor of `StreamMessageListViewTheme` -- `MessageListViewThemeData` in favor of `StreamMessageListViewThemeData` -- `MessageSearchListView` in favor of `StreamMessageSearchListView` -- `MessageSearchListViewTheme` in favor of `StreamMessageSearchListViewTheme` -- `MessageSearchListViewThemeData` in favor of `StreamMessageSearchListViewThemeData` -- `MessageReactionsModal` in favor of `StreamMessageReactionsModal` -- `MessageSearchItem` in favor of `StreamMessageSearchItem` -- `MessageSearchListView` in favor of `StreamMessageSearchListView` -- `MessageText` in favor of `StreamMessageText` -- `MessageWidget` in favor of `StreamMessageWidget` -- `MessageThemeData` in favor of `StreamMessageThemeData` -- `MultiOverlay` in favor of `StreamMultiOverlay` -- `OptionListTile` in favor of `StreamOptionListTile` -- `QuotedMessageWidget` in favor of `StreamQuotedMessageWidget` -- `ReactionBubble` in favor of `StreamReactionBubble` -- `ReactionIcon` in favor of `StreamReactionIcon` -- `ReactionPicker` in favor of `StreamReactionPicker` -- `SendingIndicator` in favor of `StreamSendingIndicator` -- `SystemMessage` in favor of `StreamSystemMessage` -- `TextTheme` in favor of `StreamTextTheme` -- `ThreadHeader` in favor of `StreamThreadHeader` -- `TypingIndicator` in favor of `StreamTypingIndicator` -- `UnreadIndicator` in favor of `SteamUnreadIndicator` -- `UploadProgressIndicator` in favor of `StreamUploadProgressIndicator` -- `UrlAttachment` in favor of `StreamUrlAttachment` -- `UserAvatar` in favor of `StreamUserAvatar` -- `UserItem` in favor of `StreamUserItem` -- `UserListView` in favor of `StreamUserListView` -- `UserListViewTheme` in favor of `StreamUserListViewTheme` -- `UserListViewThemeData` in favor of `StreamUserListViewThemeData` -- `UserMentionTile` in favor of `StreamUserMentionTile` -- `UserMentionsOverlay` in favor of `StreamUserMentionsOverlay` -- `VideoAttachment` in favor of `StreamVideoAttachment` -- `VideoService` in favor of `StreamVideoService` -- `VideoThumbnailImage` in favor of `StreamVideoThumbnailImage` -- `VisibleFootnote` in favor of `StreamVisibleFootnote` - -## ChannelListView to StreamChannelListView - -The `ChannelListView` widget has been deprecated, and it is now recommended to use `StreamChannelListView`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `StreamChannelListController`. This controller manages the content for a channel list; it lets you perform tasks such as: - -- Load initial data. -- Use channel events handlers. -- Load more data using `loadMore`. -- Replace the previously loaded channels. -- Return/Create a new channel and start watching it. -- Pause and Resume all subscriptions added to this composite. - -For more information see the [`StreamChannelListView` documentation](../../02-stream_chat_flutter/04-channel_list/stream_channel_list_view.mdx). - -### ChannelsBloc to StreamChannelListController - -The `ChannelsBloc` widget should be replaced with `StreamChannelListController`. This controller provides all the functionality needed to query and manipulate channel data previously accessible through `ChannelsBloc`. - -For more information see the [`StreamChannelListController` documentation](../../04-stream_chat_flutter_core/stream_channel_list_controller.mdx). - -### StreamChannelListView Examples - -Let's explore some examples of the functional differences when using the new `StreamChannelListView`. - -The **StreamChannelListController** provides various methods, such as: - -- **`deleteChannel`** -- **`loadMore`** -- **`muteChannel`** -- **`deleteChannel`** - -For a complete list with additional information, see the code documentation. - -#### Basic Use - -The following code demonstrates the old way of creating a **ChannelListPage**, that displays a list of channels: - -```dart -class ChannelListPage extends StatelessWidget { - const ChannelListPage({ - Key? key, - }) : super(key: key); - - @override - // ignore: prefer_expression_function_bodies - Widget build(BuildContext context) { - return Scaffold( - body: ChannelsBloc( - child: ChannelListView( - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - sort: const [SortOption('last_message_at')], - limit: 20, - channelWidget: const ChannelPage(), - ), - ), - ); - } -} -``` - -In **v4** this can now be achieved with the following: - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -As you can see, the **ChannelsBloc** has been replaced with a **StreamChannelListController**, where the **filter**, **limit**, and **sort** arguments can be set. The above code also demonstrates how to refresh the channel list by calling `_controller.refresh()`. - -## MessageSearchListView to StreamMessageSearchListView - -The `MessageSearchListView` widget has been deprecated, and it is now recommended to use `StreamMessageSearchListView`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `StreamMessageSearchListController`. This controller manages the content when searching for a message; it lets you perform tasks such as: - -- Load initial data. -- Set filters and search terms. -- Load more data using `loadMore`. -- Refresh data. - -For more information see the [`StreamMessageSearchListView` documentation](../../02-stream_chat_flutter/06-message_list/stream_message_search_list_view.mdx). - -### MessageSearchBloc to StreamMessageSearchListController - -The `MessageSearchBloc` widget should be replaced with a `StreamMessageSearchListController`. This controller provides all the functionality needed to query and manipulate message search data previously accessible through `MessageSearchBloc`. - -For more information see the [`StreamMessageSearchListController` documentation](../../04-stream_chat_flutter_core/stream_message_search_list_controller.mdx). - -### StreamMessageSearchListView Example - -The following code demonstrates the old way of searching for messages: - -```dart -class SearchExample extends StatelessWidget { - const SearchExample({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return MessageSearchBloc( - child: MessageSearchListView( - showErrorTile: true, - messageQuery: 'message query', - filters: Filter.in_('members', const ['user-id']), - sortOptions: const [ - SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - pullToRefresh: false, - limit: 30, - emptyBuilder: (context) => const Text('Nothing to show'), - itemBuilder: (context, messageResponse) { - /// Return widget - } - onItemTap: (messageResponse) { - /// Handle on tap - } - ), - ); - } -} -``` - -In **v4**, this can now be achieved with the following: - -```dart -class SearchExample extends StatefulWidget { - const SearchExample({ - Key? key, - }) : super(key: key); - - @override - State createState() => _SearchExampleState(); -} - -class _SearchExampleState extends State { - late final StreamMessageSearchListController _messageSearchListController = - StreamMessageSearchListController( - client: StreamChat.of(context).client, - filter: Filter.in_('members', [StreamChat.of(context).currentUser!.id]), - limit: 5, - searchQuery: '', - sort: [ - const SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - ); - - search() { - _messageSearchListController.searchQuery = 'search-value'; - _messageSearchListController.doInitialLoad(); - } - - @override - dispose() { - _messageSearchListController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return StreamMessageSearchListView( - controller: _messageSearchListController, - emptyBuilder: (context) => const Text('Nothing to show'), - itemBuilder: ( - context, - messageResponses, - index, - defaultWidget, - ) { - return defaultWidget.copyWith(); // modify default widget - }); - } -} -``` - -## UserListView to StreamUserListView - -The `UserListView` widget has been deprecated, and it is now recommended to use `StreamUserListView`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `StreamUserListController`. This controller manages the content when retrieving Stream users; it let's you perform tasks, such as: - -- Load data. -- Set filters. -- Refresh data. - -For more information see the [`StreamUserListView` documentation](../../02-stream_chat_flutter/09-user_list/stream_user_list_view.mdx). - -### UsersBloc to StreamUserListController - -The `UsersBloc` widget should be replaced with a `StreamUserListController`. This controller provides all the functionality needed to query and manipulate user data previously accessible through `UsersBloc`. - -For more information see the [`StreamUserListController` documentation](../../04-stream_chat_flutter_core/stream_user_list_controller.mdx). - -### StreamUserListView Example - -The following code demonstrates the old way of displaying all users: - -```dart -class UsersExample extends StatelessWidget { - const UsersExample({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return UsersBloc( - child: UserListView( - groupAlphabetically: true, - onUserTap: (user, _) { - /// Handle on tap - }, - limit: 25, - filter: Filter.and([ - Filter.autoComplete('name', 'some-name'), - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]), - sort: const [ - SortOption( - 'name', - direction: 1, - ), - ], - ), - ); - } -} -``` - -In **v4**, this can now be achieved with the following: - -```dart -class UsersExample extends StatefulWidget { - const UsersExample({ - Key? key, - }) : super(key: key); - - @override - State createState() => _UsersExampleState(); -} - -class _UsersExampleState extends State { - late final userListController = StreamUserListController( - client: StreamChat.of(context).client, - limit: 25, - filter: Filter.and([ - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - void _load() { - userListController.filter = Filter.and([ - Filter.autoComplete('name', 'some-name'), - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]); - userListController.doInitialLoad(); - } - - @override - dispose() { - userListController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return StreamUserListView( - controller: userListController, - onUserTap: (user) { - /// Handle on tap - }, - emptyBuilder: (context) => const Text('Nothing to show'), - itemBuilder: ( - context, - users, - index, - defaultWidget, - ) { - return defaultWidget.copyWith(); // modify default widget - }, - ); - } -} -``` - -## MessageInput to StreamMessageInput - -The `MessageInput` widget has been deprecated, and it is now recommended to use `StreamMessageInput`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `MessageInputController`. This controller maintains the state of the message input and exposes various methods to allow you to customize and manipulate the underlying **Message** value. - -Creating a separate controller allows easier control over the message input content by moving logic out of the deprecated `MessageInput` and into the controller. This controller can then be created, managed, and exposed in whatever way you like. - -The widget is also separated into smaller components: `StreamCountDownButton`, `StreamAttachmentPicker`, etc. - -> ❗The `MessageInputController` is exposed by the **`stream_chat_flutter_core`** package. This allows you to use the controller even if you're not using the UI components. - -As a result of this extra control, it is no longer needed for the new `StreamMessageInput` widget to expose these `MessageInput` arguments: - -- `parentMessage`: parent message in case of a thread -- `editMessage`: message to edit -- `initialMessage`: message to start with -- `quotedMessage`: message to quote/reply -- `onQuotedMessageCleared`: callback for clearing quoted message -- `textEditingController`: the text controller of the text field - -The following arguments are newly introduced to the `StreamMessageInput`, and are not available on the old `MessageInput`: - -- `messageInputController`: the controller for the message input -- `attachmentsPickerBuilder`: builder for bottom sheet when attachment picker is opened -- `sendButtonBuilder`: builder for creating send button -- `validator`: a callback function that validates the message -- `restorationId`: restoration ID to save and restore the state of the MessageInput -- `enableSafeArea`: wraps the **StreamMessageInput** widget with a **SafeArea** widget -- `elevation`: elevation of the **StreamMessageInput** widget -- `shadow`: **Shadow** for the **StreamMessageInput** widget - -For more information see the [`StreamMessageInput` documentation](../../04-stream_chat_flutter_core/stream_message_input_controller.mdx). - -### StreamMessageInput Examples - -Let's explore some examples of the functional differences when using the new `StreamMessageInput`. - -#### Basic Use - -Unless you want to programmatically manipulate the value of the message input, then there is no difference in how you would use the message input widget. - -The following code demonstrates the old way of creating a **ChannelPage** widget that displays a chat screen: - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: const ChannelHeader(), - body: Column( - children: const [ - Expanded( - child: MessageListView(), - ), - MessageInput(), - ], - ), - ); - } -} -``` - -In **v4** this is the same, the only difference being that all the Stream widgets are now prefixed with **Stream**. For example, **MessageListView** becomes **StreamMessageListView**, and so forth. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) => Scaffold( - appBar: const StreamChannelHeader(), - body: Column( - children: const [ - Expanded( - child: StreamMessageListView(), - ), - StreamMessageInput(), - ], - ), - ); -} -``` - -However, you can optionally pass in a **MessageInputController** in the **StreamMessageInput**, which gives extra control over the message input value. - -#### Thread Page - -The following code demonstrates the old way of creating a thread page: - -```dart -class ThreadPage extends StatelessWidget { - const ThreadPage({ - Key? key, - this.parent, - }) : super(key: key); - - final Message? parent; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: ThreadHeader( - parent: parent!, - ), - body: Column( - children: [ - Expanded( - child: MessageListView( - parentMessage: parent, - ), - ), - MessageInput( - parentMessage: parent, - ), - ], - ), - ); - } -} -``` - -In **v4** the only difference is the **Stream** prefix and the way that the parent message is passed to the message input: - -```dart -class ThreadPage extends StatelessWidget { - const ThreadPage({ - Key? key, - this.parent, - }) : super(key: key); - - final Message? parent; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: StreamThreadHeader( - parent: parent!, - ), - body: Column( - children: [ - Expanded( - child: StreamMessageListView( - parentMessage: parent, - ), - ), - StreamMessageInput( - messageInputController: MessageInputController( - message: Message(parentId: parent!.id), - ), - ), - ], - ), - ); - } -} -``` - -To send a thread message, you need to specify the message's parent ID for which you're creating a thread. - -#### Reply/Quote Message - -The following code demonstrates the old way of replying to a message: - -```dart -... - -void _reply(Message message) { - setState(() => _quotedMessage = message); -} - -... - -MessageInput - quotedMessage: _quotedMessage, - onQuotedMessageCleared: () { - setState(() => _quotedMessage = null); - }, -), -``` - -To reply to a message in **v4**: - -```dart -... - -void _reply(Message message) { - _messageInputController.quotedMessage = message; -} - -... - -StreamMessageInput( - messageInputController: _messageInputController, -), -``` - -The controller makes it much simpler to dynamically modify the message input. - -## Stream Chat Flutter Core - -Various changes have been made to the Core package, most notably, the introduction of all of the controllers mentioned above. - -These controllers replace the business logic implementations (Bloc). Please note that this is not related to the well-known Flutter Bloc package, but instead refers to the naming we used for our business logic components. - -In this version we're introducing controllers in place of their bloc counterparts: -**StreamChannelListController** in favor of **ChannelsBloc** -**StreamMessageSearchListController** in favor of **MessageSearchBloc** -**StreamUserListController** in favor of **UsersBloc** - -The Bloc components are deprecated in v4.0.0 but can still be used. They will be removed in the next major release (v5.0.0). - -Additionally, we also now have the **StreamMessageInputController**, as discussed above. This can be used outside of our UI package as well. - -Finally, the following Core builders are also deprecated as their functionality can be replaced using their controller counterparts: - -- ChannelListCore -- MessageSearchListCore -- UserListCore diff --git a/docusaurus/docs/Flutter/05-guides/08-migrations/migration_guide_5_0.mdx b/docusaurus/docs/Flutter/05-guides/08-migrations/migration_guide_5_0.mdx deleted file mode 100644 index 553b194754..0000000000 --- a/docusaurus/docs/Flutter/05-guides/08-migrations/migration_guide_5_0.mdx +++ /dev/null @@ -1,174 +0,0 @@ ---- -id: migration_guide_5_0 -title: v5.0 -slug: /guides/migration_guide_5_0/ ---- - -**Version 5.0.0** of the Stream Chat Flutter SDK UI package has been overhauled to support larger screen sizes better and provide native feeling web and desktop platform interactions that feel intuitive and expected. - -These newly introduced changes are platform-dependent and will not affect your current Android and iOS builds. - -This guide enumerates and better explains the SDK changes introduced in v5. - -If you find any bugs or have any questions, please file an [issue on our GitHub repository](https://github.com/GetStream/stream-chat-flutter/issues). We want to support you as much as we can with this migration. - -Code examples: - -- See our [Stream Chat Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) for an up-to-date guide using the latest Stream Chat version. -- See the [Stream Flutter Samples repository](https://github.com/GetStream/flutter-samples) with our full fledged messaging [sample application](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). - -Our documentation has also been updated to support v5, so all guides and examples will have updated code. - -### Dependencies - -To migrate to v5.0.0, update your `pubspec.yaml` with the correct Stream chat package you're using: - -```yaml -dependencies: - stream_chat_flutter: ^5.0.0 # full UI, core and client packages - stream_chat_flutter_core: ^5.0.0 # core and client packages - stream_chat: ^5.0.0 # client package -``` - ---- - -## Desktop and Web Support: What Changed? - -This section highlights our efforts on Desktop (macOS, Windows, and Linux) and Web support. - -### Setup - -See the [setup guide](/flutter/v5/stream_chat_flutter/setup) for platform specific instructions. - -### Supporting Larger Screens - -We've added support for larger screens and have made changes to the UI to support larger screen sizes better. - -- Widgets are constrained to a maximum size, for example, appropriate message sizing for larger screens. -- UI changes to use larger screen real estate. For example, reactions are added to the bottom of a message on desktop and web. - -Below is an example running on macOS, with a split-screen view showing channels on the left and messages on the right. - -![MacOS split](../../../../flutter_versioned_docs/version-5.x.x/assets/mac_os_split.png) - -### Native Platform Interactions - -The user experience of interacting with a desktop application differs from a mobile counterpart. There are several factors to consider for an application to feel native and intuitive on the platform it is running, for example: - -- Input controls: touch, keyboard, and mouse interactions -- Native file system or gallery access (as well as sharing functionality) -- Shortcuts -- Dialog screens - -By default, Stream Chat Flutter will use the correct input controls and visual elements for the target platform. For example, touch and swipe controls will be the default on mobile, while on web and desktop these will be disabled and interactions with the mouse and keyboard will be preferred. - -On desktop and web it's also possible to add attachments by simply dragging them into the message input box. - -### All UI/Behaviour Changes for Desktop and Web - -- Right-click context menus for messages and full-screen attachments. -- Upload and download attachments using the native desktop file system. -- Press the "enter" key to send a message. -- If you are quoting a message and have not yet typed any text, you can press the `"esc"` key to remove the quoted message. -- A dedicated "X" button for removing a quoted message with your mouse. -- Drag and drop attachment files to `StreamMessageInput`. -- New `StreamMessageInput.draggingBorder` property to customize the border color of the message input when dropping a file. -- Message reactions bubbles differ per platform. -- Hovering over a message reaction will show the users that have reacted to the message. -- Desktop attachment sharing UI. -- Selectable message text with mouse input. -- Gallery navigation controls with keyboard shortcuts (left and right arrow keys). -- Appropriate message sizing for large screens. -- Right-click context menu for `StreamMessageListView` items. -- `StreamMessageListView` items not swipe-able on desktop & web. -- Video support for Windows & Linux through `dart_vlc`. -- Video support for macOS through `video_player_macos`. -- Replace bottom sheets with dialog screens where appropriate. - -## What's New? - -We improved the overall user experience of the Stream Chat Flutter SDK and added new features to make it easier to customize the SDK to your needs. - -We've also fixed several bugs and improved the overall stability of the SDK. - -### StreamChatConfiguration - -The `StreamChatConfiguration` class is a new inherited widget that allows you to configure the Stream Chat Flutter SDK. - -It provides a few configuration options. For example, it lets you specify if you want to `enforceUniqueReactions` or not and allows you to set the `reactionIcons` to use in your app. - -You can retrieve the current configuration using `StreamChatConfiguration.of(context)`, as long as there is a `StreamChat` or `StreamChatConfiguration` widget higher up the widget tree. You can provide a custom `StreamChatConfigurationData` directly to `StreamChat` or wrap a section of the widget tree with a `StreamChatConfiguration`. - -For additional information, see [#1125](https://github.com/GetStream/stream-chat-flutter/issues/1125). The `defaultUserImage`, `placeholderUserImage`, `reactionIcons`, and `enforceUniqueReactions` have been refactored out of `StreamChatThemeData` and into the new`StreamChatConfigurationData` class. - -### StreamMemberListView and StreamMemberGridView - -The `StreamMemberListView` and `StreamMemberGridView` widgets are new widgets that allow you to display a list of members in a channel. - -Check out the dedicated [documentation](/flutter/v5/stream_chat_flutter/stream_member_list_view) for more information. - -### Attachment Picker - -As part of the v5 release, we've refactored the `AttachmentPicker` to be more flexible and customizable. This allows you to use the `AttachmentPicker` in various ways and customize the UI to your liking. - -Check out the dedicated [guide](/flutter/v5/customization/custom-widgets/customize_attachment_picker_modal) for more information. - -### Other Changes - -The following was also introduced: - -- Added support for additional text field parameters in`StreamMessageInput`: `maxLines`, `minLines`, `textInputAction`, `keyboardType`, and `textCapitalization`. -- Added `showStreamAttachmentPickerModalBottomSheet` to show the attachment picker modal bottom sheet. -- Added `onQuotedMessageCleared` to `StreamMessageInput` -- `selected` and `selectedTileColor` to `StreamChannelListTile` -- Added `AttachmentUploadStateBuilder.inProgressBuilder` to `AttachmentUploadStateBuilder` -- Added `AttachmentUploadStateBuilder.successBuilder` to `AttachmentUploadStateBuilder` -- Added `AttachmentUploadStateBuilder.failedBuilder` to `AttachmentUploadStateBuilder` -- Added `StreamAutocomplete` widget for auto-complete triggers in `StreamMessageInput`. -- Added `StreamMessageInput.customAutocompleteTriggers` to allow users to define their custom triggers. - -New translations: - -- `couldNotReadBytesFromFileError` -- `downloadLabel` -- `toggleMuteUnmuteAction` -- `toggleMuteUnmuteGroupQuestion` -- `toggleMuteUnmuteGroupText` -- `toggleMuteUnmuteUserQuestion` -- `toggleMuteUnmuteUserText` - -## Deprecated - -The following components have been deprecated in v5.0.0: - -- Deprecated `showConfirmationDialog` in favor of `showConfirmationBottomSheet` -- Deprecated `showInfoDialog` in favor of `showInfoBottomSheet` -- Deprecated `wrapAttachmentWidget` in favor of the `WrapAttachmentWidget` class - -## Breaking changes - -The following components have been removed in v5.0.0: - -- `StreamImageAttachment.size` has been removed in favor of `StreamImageAttachment.constraints`. -- `StreamFileAttachment.size` has been removed in favor of `StreamFileAttachment.constraints`. -- `StreamGiphyAttachment.size` has been removed in favor of `StreamGiphyAttachment.constraints`. -- `StreamVideoAttachment.size` has been removed in favor of `StreamVideoAttachment.constraints`. -- `StreamVideoThumbnailImage.width` and `StreamVideoThumbnailImage.height` have been removed in favor of `StreamVideoThumbnailImage.constraints`. - -To fix these deprecations in your code, you can use a `BoxConstraints.tight` passing the desired fixed size as a parameter. - -```dart -/// BEFORE -StreamImageAttachment( - size: size, -) - -/// AFTER -StreamImageAttachment( - constraints: BoxConstraints.tight(size), -) -``` - -- Removed `StreamMessageInput.customOverlays` in favor of `StreamMessageInput.customAutocompleteTriggers`. Read the guide on [Adding Custom Autocomplete Triggers](/flutter/v5/customization/custom-widgets/autocomplete_triggers) to learn how to migrate your code. - -- Removed the default emoji overlay picker. Read the guide on [Adding Custom Autocomplete Triggers](/flutter/v5/customization/custom-widgets/autocomplete_triggers) to learn how to migrate your code. diff --git a/docusaurus/docs/Flutter/05-guides/08-migrations/migration_guide_7_0.mdx b/docusaurus/docs/Flutter/05-guides/08-migrations/migration_guide_7_0.mdx deleted file mode 100644 index ad2d6dcc0f..0000000000 --- a/docusaurus/docs/Flutter/05-guides/08-migrations/migration_guide_7_0.mdx +++ /dev/null @@ -1,158 +0,0 @@ ---- -id: migration_guide_7_0 -title: v7.0 -slug: /guides/migration_guide_7_0/ ---- - -This guide enumerates and better explains the SDK changes introduced in v7. - -If you find any bugs or have any questions, please file an [issue on our GitHub repository](https://github.com/GetStream/stream-chat-flutter/issues). We want to support you as much as we can with this migration. - -Code examples: - -- See our [Stream Chat Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) for an up-to-date guide using the latest Stream Chat version. -- See the [Stream Flutter Samples repository](https://github.com/GetStream/flutter-samples) with our full fledged messaging [sample application](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). - -Our documentation has also been updated to support v7, so all guides and examples will have updated code. - -### Dependencies - -To migrate to v7.0.0, update your `pubspec.yaml` with the correct Stream chat package you're using: - -```yaml -dependencies: - stream_chat_flutter: ^7.0.0 # full UI, core and client packages - stream_chat: ^7.0.0 # client package -``` - ---- - -## What's New? - -We improved the overall user experience of the Stream Chat Flutter SDK and added new features to make it easier to customize the SDK to your needs. - -We've also fixed several bugs and improved the overall stability of the SDK. - -Added support for `StreamMessageInput.contentInsertionConfiguration` to specify the content insertion configuration. - - ```dart - StreamMessageInput( - ..., - contentInsertionConfiguration: ContentInsertionConfiguration( - onContentInserted: (content) { - // Do something with the content. - controller.addAttachment(...); - }, - ), - ) - ``` -## Breaking changes - -The following components have been removed in v7.0.0: - -- `ChatPersistenceClient.getChannelStates.sort` has been removed in favor of `ChatPersistenceClient.getChannelStates.channelStateSort`. -```dart -/// BEFORE -chatPersistenceClient.getChannelStates( - ... - sort: [SortOption('last_message_at')], -) - -/// AFTER -chatPersistenceClient.getChannelStates( - ... - channelStateSort: [SortOption('last_message_at')], -) -``` -- `StreamChatClient.queryChannels.sort` has been removed in favor of `StreamChatClient.queryChannels.channelStateSort`. -```dart -/// BEFORE -streamChatClient.getChannelStates( - ... - sort: [SortOption('last_message_at')], -) - -/// AFTER -streamChatClient.getChannelStates( - ... - channelStateSort: [SortOption('last_message_at')], -) -``` -- `MessageWidget.customAttachmentBuilders` has been removed in favor of `MessageWidget.attachmentBuilders`. -```dart -/// BEFORE -MessageWidget( - customAttachmentBuilders: { - 'image': (context, message, attachment) => // build image attachment, - }, - ... -) -``` -```dart -/// AFTER -class CustomImageAttachmentBuilder extends StreamAttachmentWidgetBuilder { - @override - bool canHandle( - Message message, - Map> attachments, - ) { - // Custom logic to check - // if the attachment can be handled by this builder - ... - } - - @override - Widget build( - BuildContext context, - Message message, - Map> attachments, - ) { - // custom build implementation - ... - } -} - -MessageWidget( - attachmentBuilders: const [CustomImageAttachmentBuilder()], - ... -) -``` -- `RetryPolicy.retryTimeout` has been removed in favor of `RetryPolicy.delayFactor`. -- `StreamChatNetworkError.fromDioError` has been removed in favor of `StreamChatNetworkError.fromDioException`. -- `MessageSendingStatus` has been removed in favor of `MessageState`. -- `StreamChannelListController.sort` has been removed in favor of `StreamChannelListController.channelStateSort`. -- `ChannelPreview` has been removed in favor of `StreamChannelListTile`. -- `ChannelPreviewBuilder` has been removed in favor of `StreamChannelListViewIndexedWidgetBuilder`. -- `StreamUserItem` has been removed in favor of `StreamUserListTile`. -- `ReturnActionType` has been removed and no longer used. -- `StreamMessageInput.attachmentThumbnailBuilders` has been removed in favor of `StreamMessageInput.mediaAttachmentBuilder`. -- `MessageWidget.showReactionPickerIndicator` has been removed in favor of `MessageWidget.showReactionPicker`. -- `MessageWidget.bottomRowBuilder` has been removed in favor of `MessageWidget.bottomRowBuilderWithDefaultWidget`. -- `MessageWidget.deletedBottomRowBuilder` has been removed in favor of `MessageWidget.deletedBottomRowBuilderWithDefaultWidget`. -- `MessageWidget.usernameBuilder` has been removed in favor of `MessageWidget.usernameBuilderWithDefaultWidget`. -- `MessageWidget.showReactionPickerTail` has been removed in favor of `MessageWidget.showReactionPicker`. -- `MessageTheme.linkBackgroundColor` has been removed in favor of `MessageTheme.urlAttachmentBackgroundColor`. -- `showConfirmationDialog` has been removed in favor of `showConfirmationBottomSheet`. -- `showInfoDialog` has been removed in favor of `showInfoBottomSheet`. -- `wrapAttachmentWidget` has been removed in favor of `WrapAttachmentWidget`. -- `MessageListView.onMessageSwiped` parameter. Try wrapping the `MessageWidget` with a `Swipeable`, `Dismissible` or a custom widget to achieve the swipe to reply behaviour. -```dart -/// BEFORE -MessageListView( - onMessageSwiped: (Message message) => // handle swipe, - ... -) - -/// AFTER -MessageListView( - messageBuilder: (BuildContext context, Message message) => - Swipeable( - key: ValueKey(message.id), - onSwiped: (_) => // handle swipe, - child: StreamMessageWidget( - message: message, - ... - ), - ), -) -``` diff --git a/docusaurus/docs/Flutter/05-guides/08-migrations/migration_guide_8_0.mdx b/docusaurus/docs/Flutter/05-guides/08-migrations/migration_guide_8_0.mdx deleted file mode 100644 index e8f97bfc35..0000000000 --- a/docusaurus/docs/Flutter/05-guides/08-migrations/migration_guide_8_0.mdx +++ /dev/null @@ -1,57 +0,0 @@ ---- -id: migration_guide_8_0 -title: v8.0 -slug: /guides/migration_guide_8_0/ ---- - -This guide enumerates and better explains the SDK changes introduced in v8. - -If you find any bugs or have any questions, please file an [issue on our GitHub repository](https://github.com/GetStream/stream-chat-flutter/issues). We want to support you as much as we can with this migration. - -Code examples: - -- See our [Stream Chat Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) for an up-to-date guide using the latest Stream Chat version. -- See the [Stream Flutter Samples repository](https://github.com/GetStream/flutter-samples) with our full fledged messaging [sample application](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). - -Our documentation has also been updated to support v8, so all guides and examples will have updated code. - -### Dependencies - -To migrate to v8.0.0, update your `pubspec.yaml` with the correct Stream chat package you're using: - -```yaml -dependencies: - stream_chat_flutter: ^8.0.0 # full UI, core and client packages - stream_chat: ^8.0.0 # client package -``` - ---- - -## Important notes - -- The package from recent versions has been restricted to Flutter 3.19+ as we generally aim to support -the latest and the previous version of Flutter when possible. - -- The `attachmentBuilders` parameter in the `StreamMessageListView` now only expect custom attachments -and does not need the default attachment builders. You can also use `StreamAttachmentWidgetBuilder.defaultBuilders` -to add the default builders if necessary. - -## Breaking changes - -Version 8.0 has two main breaking changes. - -### Removal of the `useMaterial3` flag - -In v7, we introduced a temporary `useMaterial3` flag that allows users to optionally use Material3 styling in Stream components. -This was necessary at the time for various reasons. - -However, this flag is now removed and Material3 will be the default styling for all components. - -### Connectivity stream changes - -While this is a not directly a user-facing change, it is added here for completeness of the list. - -The `StreamChat` widget has a `connectivityStream` parameter to allow testing of various scenarios. -Due to changes in the relevant package, it was necessary to change the type of the stream from -`Stream?` to `Stream>?`. - diff --git a/docusaurus/docs/Flutter/05-guides/09-initialize_stream_chat_widget_tree.mdx b/docusaurus/docs/Flutter/05-guides/09-initialize_stream_chat_widget_tree.mdx deleted file mode 100644 index 9207d4585a..0000000000 --- a/docusaurus/docs/Flutter/05-guides/09-initialize_stream_chat_widget_tree.mdx +++ /dev/null @@ -1,699 +0,0 @@ ---- -id: initialize_stream_chat_widget_tree -title: Initialize Stream Chat in Part of the Widget Tree ---- - -If you’re creating a full-scale chat application, you probably want to have Stream Chat Flutter initialized at the top of your widget tree and the Stream user connected as soon as they open the application. - -However, if you only need chat functionality in a part of your application, then it’ll be better to delay Stream Chat initialization to when it’s needed. -This guide demonstrates three alternative ways for you to initialize Stream Chat Flutter for a part of your widget tree and to only connect a user when needed. - -## What To Keep In Mind? - -Before investigating potential solutions, let’s first take a look at the relevant Stream Chat widgets and classes. - -Most of the Stream Chat Flutter UI widgets rely on having a [StreamChat](../02-stream_chat_flutter/stream_chat_and_theming.mdx) ancestor in the widget tree. -The **StreamChat** widget is an [InheritedWidget](https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html) that exposes the **StreamChatClient** through **BuildContext**. -This widget also initializes the [StreamChatCore](../04-stream_chat_flutter_core/stream_chat_core.mdx) widget and the **StreamChatTheme**. - -**StreamChatCore** is a **StatefulWidget** used to react to life cycle changes and system updates. -When the app goes into the background, the WebSocket connection is closed. -Conversely, a new connection is initiated when the app is back in the foreground. - -What is important to take note of is that **a connection is only established if a user is connected**. - -This means that if you have not yet called `client.connectUser(user, token)`, no connection will be made, and only background listeners will be registered to determine the app's foreground state. - -## Option 1: Builder and Connect/Disconnect User - -This option requires you to wrap your whole application with the **StreamChat** widget and to call `connectUser` and `disconnectUser` as needed. - -This option is the easiest, however, it requires **StreamChat** to be at the top of each route and as a result, will have a slight overhead as it’ll create the above-mentioned Stream widgets that may not yet be needed. - -### Exposing the StreamChat Widget - -First, you must expose the client and base Stream Chat widgets to the whole application. - -```dart -void main() { - final client = StreamChatClient( - 'q29npdvqjr99', - logLevel: Level.OFF, - ); - - 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) { - return StreamChat(client: client, child: child); - }, - home: const HomeScreen(), - ); - } -} -``` - -In the above code, you: - -1. Create a **StreamChatClient** instance -2. Pass the instance to the **StreamChat** widget -3. Expose **StreamChat** to the whole application within the **MaterialApp** `builder` - -A few important things to note: - -- The `builder` wraps the **StreamChat** widget for every route of our application. No matter where you are in the widget tree, you’ll be able to call `StreamChat.of(context)`. -- The state will only be created once for our application, as **StreamChat** is a **StatefulWidget** and the position of **StreamChat** in the widget tree remains the same throughout the application lifecycle. -- No connection will be made until you call `connectUser`. - -### Connecting and Disconnecting Users - -In **MaterialApp** above, the home page is set to **HomeScreen**. This screen could look something like the following: - -```dart -class HomeScreen extends StatelessWidget { - const HomeScreen({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(), - body: const Center( - child: Text('Home Screen'), - ), - floatingActionButton: FloatingActionButton( - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute(builder: (context) => const ChatSetup())); - }, - child: const Icon( - Icons.message, - ), - ), - ); - } -} -``` - -This screen shows a floating action button that on click navigates the user to the **ChatSetup**. We want to connect and disconnect a Stream user only when they go to the chat setup screen. - -```dart -class ChatSetup extends StatefulWidget { - const ChatSetup({ - super.key, - }); - - @override - State createState() => _ChatSetupState(); -} - -class _ChatSetupState extends State { - late final Future connectionFuture; - late final client = StreamChat.of(context).client; - - @override - void initState() { - super.initState(); - connectionFuture = client.connectUser( - User(id: 'USER_ID'), - 'TOKEN', - ); - } - - @override - void dispose() { - client.disconnectUser(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(), - body: FutureBuilder( - future: connectionFuture, - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return const Center( - child: CircularProgressIndicator(), - ); - default: - if (snapshot.hasError) { - return Text('Error: ${snapshot.error}'); - } else { - return const ChannelListPage(); - } - } - }, - ), - ); - } -} -``` - -Within `initState` you call `connectUser`; once the future for `connectUser` has completed a connection to the Stream API is established, you can then display the relevant Stream Chat UI widgets. - -Once the **ChatScreen** widget is disposed of, then `disconnectUser` will be called within the `dispose` method. - -### Caution - -In this example, `disconnectUser` will **only** be called when the **ChatSetup** widget is disposed. - -You need to ensure that this widget (route) is completely disposed of, or you need to call `disconnectUser` and `connectUser` manually when navigating to relevant parts of your application. - -For example, let’s say you have a button within one of the chat screens to navigate to a completely different part of your app, then you want to make sure the **ChatScreen** route is disposed of by forcing it to be removed: - -```dart -Navigator.of(context).pushAndRemoveUntil( - MaterialPageRoute( - builder: ((context) => const HomeScreen()), - ), - (Route route) => false, -); -``` - -Or let’s say you wanted to pop back to the first route: - -```dart -Navigator.of(context).popUntil((route) => route.isFirst); -``` - -Both of these will ensure the route is disposed of and the user is disconnected as a result. - -## Option 2: A Nested Navigator - -Another approach would be to introduce a new [Navigator](https://api.flutter.dev/flutter/widgets/Navigator-class.html). -This has the benefit that everything related to Stream chat is contained to a specific part of the widget tree. - -### Defining Routes and Nested Routes - -In this example, our application has the following routes. - -```dart -const routeHome = '/'; -const routePrefixChat = '/chat/'; -const routeChatHome = '$routePrefixChat$routeChatChannels'; -const routeChatChannels = 'chat_channels'; -const routeChatChannel = 'chat_channel'; -``` - -For the `/chat/` nested routes (**routePrefixChat**), this approach initializes Stream Chat in our application and introduces a nested navigator. - -Let’s explore the code: - -```dart -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatefulWidget { - const MyApp({ - Key? key, - }) : super(key: key); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - final GlobalKey navigatorKey = GlobalKey(); - - @override - Widget build(BuildContext context) { - return Provider.value( - value: navigatorKey, - child: MaterialApp( - navigatorKey: navigatorKey, - initialRoute: routeHome, - onGenerateRoute: (settings) { - late Widget page; - if (settings.name == routeHome) { - page = const HomeScreen(); - } else if (settings.name!.startsWith(routePrefixChat)) { - final subRoute = settings.name!.substring(routePrefixChat.length); - page = ChatSetup( - setupChatRoute: subRoute, - ); - } else { - throw Exception('Unknown route: ${settings.name}'); - } - - return MaterialPageRoute( - builder: (context) { - return page; - }, - settings: settings, - ); - }, - ), - ); - } -} -``` - -In the above code you’re: - -1. Creating a navigator key, passing it to `MaterialApp`, and exposing it to the whole application using Provider (you can expose it however you want). -2. Creating `onGenerateRoute` that specifies what page to show depending on the route. Most importantly, if the route contains the **routePrefixChat,** it navigates to the **ChatSetup** page and passes in the remainder of the route. - -For example, `Navigator.pushNamed(context, routeChatHome)` will navigate to the **ChatSetup** page and pass in the nested route **routeChatChannels.** - -### Stream Chat Initialization, User Connection, and Nested Navigation - -Within the **ChatSetup** widget, we’ll initialize Stream chat, connect a user, and create a new Navigator that handles the sub-navigation for the chat-specific pages. - -```dart -class ChatSetup extends StatefulWidget { - const ChatSetup({Key? key, required this.setupChatRoute}) : super(key: key); - - final String setupChatRoute; - - @override - State createState() => _ChatSetupState(); -} - -class _ChatSetupState extends State { - late final Future connectionFuture; - late final client = StreamChatClient( - 'KEY', - logLevel: Level.OFF, - ); - - @override - void initState() { - super.initState(); - connectionFuture = client.connectUser( - User(id: 'USER_ID'), - 'TOKEN', - ); - } - - @override - void dispose() { - client.disconnectUser(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Material( - child: StreamChat( - client: client, - child: FutureBuilder( - future: connectionFuture, - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return const Center( - child: CircularProgressIndicator(), - ); - default: - if (snapshot.hasError) { - return Text('Error: ${snapshot.error}'); - } else { - return Navigator( - initialRoute: widget.setupChatRoute, - onGenerateRoute: _onGenerateRoute, - ); - } - } - }, - ), - ), - ); - } - - Route _onGenerateRoute(RouteSettings settings) { - late Widget page; - switch (settings.name) { - case routeChatChannels: - page = ChannelListPage( - client: client, - ); - break; - case routeChatChannel: - final channel = settings.arguments as Channel; - page = StreamChannel( - channel: channel, - child: const ChannelPage(), - ); - break; - default: - throw Exception('Unknown route: ${settings.name}'); - } - return MaterialPageRoute( - builder: (context) { - return page; - }, - settings: settings, - ); - } -} -``` - -This **ChatSetup** widget is similar to what it was in the first option, the only difference is that we’re also introducing a nested navigator and handling those nested routes. - -The steps for the above code are: - -1. Create a **StreamChatClient** instance -2. Call `connectUser` within `initState` and await the result using a **FutureBuilder** -3. Introduce a **StreamChat** widget into the widget tree -4. Introduce a new **Navigator** for the chat-specific routes -5. Call `disconnectUser` within `dispose` - -### Displaying Stream Chat UI Widgets and Global Navigation - -Then finally, the **ChannelListPage** could look something like the following: - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - void _popChatPages() { - final nav = context.read>(); - nav.currentState!.pop(); - } - - @override - Widget build(BuildContext context) { - return WillPopScope( - onWillPop: () async { - _popChatPages(); - return true; - }, - child: Scaffold( - appBar: AppBar( - leading: BackButton( - onPressed: () { - _popChatPages(); - }, - ), - ), - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) { - Navigator.pushNamed(context, routeChatChannel, - arguments: channel); - }, - ), - ), - ), - ); - } -} -``` - -There are two important things to note in the above code: - -- We’re accessing the global **NavigatorState** using Provider and calling `pop()` on the back press. This will ensure that this entire route is disposed of and that the Stream connection is closed. -- Within `onChannelTap` we’re calling `pushNamed` and passing in the route to display a single channel page. This uses the navigator introduced in **ChatSetup**, which is the closest navigator within the widget tree. - -A few things to take note of: - -- You’ll always need to access the global navigator if you want to dispose of this route. you need to ensure that this route is popped or replaced, otherwise, the Stream connection will remain active for as long as the chat route is on the stack (or manually disconnected). - -## Option 3: Navigator 2.0 - Using GoRouter - -This final example will be a combination of the first two options. The following code is an example of how to initialize Stream Chat in a part of the widget tree using the [GoRouter package](https://pub.dev/packages/go_router). This solution will change depending on how you do routing in your Flutter application and which package (if any) you use. - -### Application Routes and Conditional Stream Initialization - -For this example we have the following routes and nested routes: - -```dart -|_ '/' -> home page - |_ 'settings/' - settings page - |_ 'chat/' - chat home, shows the channels list page - |_ 'channel/' - specific channel page -``` - -In the **MyApp** widget, we’ll initialize **GoRouter** and the **StreamChatClient**. -However, we will only expose the **StreamChat** widget for certain routes. -Additionally, we’ll create a **ChatSetup** widget that connects and disconnects the user. -This widget will also **only** be injected for the `/chat` routes. - -```dart -class MyApp extends StatefulWidget { - const MyApp({ - Key? key, - }) : super(key: key); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - final _client = StreamChatClient( - 'q29npdvqjr99', - logLevel: Level.OFF, - ); - bool wasPreviousRouteChat = false; - - late final _router = GoRouter( - initialLocation: '/', - routes: [ - ShellRoute( - builder: (context, state, child) { - if (state.uri.host.startsWith('/chat')) { - wasPreviousRouteChat = true; - return StreamChat( - client: _client, - child: ChatSetup(client: _client, child: child), - ); - } else { - if (wasPreviousRouteChat) { - wasPreviousRouteChat = false; - return StreamChat( - client: _client, - child: child, - ); - } else { - return child; - } - } - }, - routes: [ - GoRoute( - path: '/', - builder: (context, state) => const HomeScreen(), - routes: [ - GoRoute( - path: 'settings', - builder: (context, state) => const SettingsPage(), - ), - GoRoute( - path: 'chat', - builder: (context, state) => const ChannelListPage(), - routes: [ - GoRoute( - path: 'channel', - builder: (context, state) { - final channel = state.extra as Channel; - return StreamChannel( - channel: channel, - child: const ChannelPage(), - ); - }, - ), - ], - ), - ], - ), - ], - ), - ], - ); - - @override - Widget build(BuildContext context) { - return MaterialApp.router( - routeInformationParser: _router.routeInformationParser, - routeInformationProvider: _router.routeInformationProvider, - routerDelegate: _router.routerDelegate, - ); - } -} -``` - -If you’re unfamiliar with GoRouter it will help to first read the documentation and then come back to this guide. - -There are a few important things to note in the above code: - -- Define our routes and nested routes -- Specify the initial route with `initialLocation` -- Use the `navigatorBuilder` to wrap certain routes with **StreamChat** and **ChatSetup**. - - The `wasPreviousRouteChat` \***\*boolean is used to determine if the previous route was a chat route. This is important because when you press the back button from the `/chat` route and navigate to the `/` route, the **StreamChat** widget still needs to be accessible while the navigation transition occurs. However, if you then navigate to the `/setting` route, you no longer need the **StreamChat\*\* widget and can safely remove it. - -### Navigating With GoRouter - -Within the **HomeScreen** you can create a button that on press navigates to the `/chat` route: - -```dart -GoRouter.of(context).go('/chat'); -``` - -### Connecting and Disconnecting Users - -Same as before, we’ll use the **ChatSetup** widget to connect and disconnect a user. -This time the widget also takes in a **child** widget to display once the connection is finished. -The child widget is dependent on the route we’re navigating to. - -```dart -class ChatSetup extends StatefulWidget { - const ChatSetup({ - Key? key, - required this.client, - required this.child, - }) : super(key: key); - - final StreamChatClient client; - final Widget child; - - @override - State createState() => _ChatSetupState(); -} - -class _ChatSetupState extends State { - late final Future connectionFuture; - - @override - void initState() { - super.initState(); - connectionFuture = widget.client.connectUser( - User(id: 'USER_ID'), - 'TOKEN', - ); - } - - @override - void dispose() { - widget.client.disconnectUser(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Material( - child: FutureBuilder( - future: connectionFuture, - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return const Center( - child: CircularProgressIndicator(), - ); - default: - if (snapshot.hasError) { - return Text('Error: ${snapshot.error}'); - } else { - return widget.child; - } - } - }, - ), - ); - } -} -``` - -This will connect the Stream chat user within `initState` and disconnect the user on `dispose`. This is similar to the previous examples we explored. - -### Displaying the Stream UI Widgets - -The **ChannelListPage** can look something like the following: - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - super.key, - }); - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final client = StreamChat.of(context).client; - late final _controller = StreamChannelListController( - client: client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(), - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) { - GoRouter.of(context).go('/chat/channel', extra: channel); - }, - ), - ), - ); - } -} -``` - -This is the same as before, the only difference is that the navigation is slightly different; now we’re navigating to the `/chat/channel` route for individual channel pages. - -## Conclusion - -This guide demonstrated three different ways to initialize Stream Chat in a part of the Flutter widget tree. - -There are two key takeaways - -1. Accessing **StreamChat** depends on your location in the widget tree -2. How you ultimately decide to expose **StreamChat** and connect users will be up to your application architecture and how you manage routing. - -The above are only examples that can be refined and tweaked to suit your needs. diff --git a/docusaurus/docs/Flutter/05-guides/_category_.json b/docusaurus/docs/Flutter/05-guides/_category_.json deleted file mode 100644 index 14a4f173f0..0000000000 --- a/docusaurus/docs/Flutter/05-guides/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Guides" -} \ No newline at end of file diff --git a/docusaurus/docs/Flutter/assets/authentication_demo_app.jpg b/docusaurus/docs/Flutter/assets/authentication_demo_app.jpg deleted file mode 100644 index eed57c3374..0000000000 Binary files a/docusaurus/docs/Flutter/assets/authentication_demo_app.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/channel_header.png b/docusaurus/docs/Flutter/assets/channel_header.png deleted file mode 100644 index 98f41c614b..0000000000 Binary files a/docusaurus/docs/Flutter/assets/channel_header.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/channel_header_custom_title.png b/docusaurus/docs/Flutter/assets/channel_header_custom_title.png deleted file mode 100644 index 65a9ee75a6..0000000000 Binary files a/docusaurus/docs/Flutter/assets/channel_header_custom_title.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/channel_list_header.png b/docusaurus/docs/Flutter/assets/channel_list_header.png deleted file mode 100644 index 6f112db9be..0000000000 Binary files a/docusaurus/docs/Flutter/assets/channel_list_header.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/channel_list_header_custom_subtitle.png b/docusaurus/docs/Flutter/assets/channel_list_header_custom_subtitle.png deleted file mode 100644 index 3c7798570a..0000000000 Binary files a/docusaurus/docs/Flutter/assets/channel_list_header_custom_subtitle.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/channel_list_view.png b/docusaurus/docs/Flutter/assets/channel_list_view.png deleted file mode 100644 index a4390c2eac..0000000000 Binary files a/docusaurus/docs/Flutter/assets/channel_list_view.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/channel_preview.png b/docusaurus/docs/Flutter/assets/channel_preview.png deleted file mode 100644 index 39f5629bb8..0000000000 Binary files a/docusaurus/docs/Flutter/assets/channel_preview.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/chat_basics.png b/docusaurus/docs/Flutter/assets/chat_basics.png deleted file mode 100644 index 82e27cfa49..0000000000 Binary files a/docusaurus/docs/Flutter/assets/chat_basics.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png b/docusaurus/docs/Flutter/assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png deleted file mode 100644 index 9e92437dbf..0000000000 Binary files a/docusaurus/docs/Flutter/assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/dashboard_firebase_enable.jpeg b/docusaurus/docs/Flutter/assets/dashboard_firebase_enable.jpeg deleted file mode 100644 index e4696ec882..0000000000 Binary files a/docusaurus/docs/Flutter/assets/dashboard_firebase_enable.jpeg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/dashboard_firebase_key.jpeg b/docusaurus/docs/Flutter/assets/dashboard_firebase_key.jpeg deleted file mode 100644 index 87243e91f6..0000000000 Binary files a/docusaurus/docs/Flutter/assets/dashboard_firebase_key.jpeg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/dashboard_save_changes.jpeg b/docusaurus/docs/Flutter/assets/dashboard_save_changes.jpeg deleted file mode 100644 index 1c58a93e63..0000000000 Binary files a/docusaurus/docs/Flutter/assets/dashboard_save_changes.jpeg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/end_to_end_encryption.png b/docusaurus/docs/Flutter/assets/end_to_end_encryption.png deleted file mode 100644 index b41e11ced6..0000000000 Binary files a/docusaurus/docs/Flutter/assets/end_to_end_encryption.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/firebase_authentication_dashboard.jpg b/docusaurus/docs/Flutter/assets/firebase_authentication_dashboard.jpg deleted file mode 100644 index c304055768..0000000000 Binary files a/docusaurus/docs/Flutter/assets/firebase_authentication_dashboard.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/firebase_cloud_secrets_management.jpg b/docusaurus/docs/Flutter/assets/firebase_cloud_secrets_management.jpg deleted file mode 100644 index 4f131df4cc..0000000000 Binary files a/docusaurus/docs/Flutter/assets/firebase_cloud_secrets_management.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png b/docusaurus/docs/Flutter/assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png deleted file mode 100644 index c5670d0dc2..0000000000 Binary files a/docusaurus/docs/Flutter/assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/firebase_project_settings.jpeg b/docusaurus/docs/Flutter/assets/firebase_project_settings.jpeg deleted file mode 100644 index 4fbc6521c3..0000000000 Binary files a/docusaurus/docs/Flutter/assets/firebase_project_settings.jpeg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/firebase_stream_chat_extension_usage.jpg b/docusaurus/docs/Flutter/assets/firebase_stream_chat_extension_usage.jpg deleted file mode 100644 index 7374a67f8a..0000000000 Binary files a/docusaurus/docs/Flutter/assets/firebase_stream_chat_extension_usage.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/hashtag_example.jpg b/docusaurus/docs/Flutter/assets/hashtag_example.jpg deleted file mode 100644 index a2bb3ba4c9..0000000000 Binary files a/docusaurus/docs/Flutter/assets/hashtag_example.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/install_stream_chat_firebase_extension.jpg b/docusaurus/docs/Flutter/assets/install_stream_chat_firebase_extension.jpg deleted file mode 100644 index 309ecce13c..0000000000 Binary files a/docusaurus/docs/Flutter/assets/install_stream_chat_firebase_extension.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/live_stream_1.jpg b/docusaurus/docs/Flutter/assets/live_stream_1.jpg deleted file mode 100644 index bef68c6edb..0000000000 Binary files a/docusaurus/docs/Flutter/assets/live_stream_1.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/live_stream_2.jpg b/docusaurus/docs/Flutter/assets/live_stream_2.jpg deleted file mode 100644 index 02a3513297..0000000000 Binary files a/docusaurus/docs/Flutter/assets/live_stream_2.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/localization_support.jpg b/docusaurus/docs/Flutter/assets/localization_support.jpg deleted file mode 100644 index 50d8b761ee..0000000000 Binary files a/docusaurus/docs/Flutter/assets/localization_support.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/location_sharing_example.jpg b/docusaurus/docs/Flutter/assets/location_sharing_example.jpg deleted file mode 100644 index 7f220379c9..0000000000 Binary files a/docusaurus/docs/Flutter/assets/location_sharing_example.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/location_sharing_example_message.jpg b/docusaurus/docs/Flutter/assets/location_sharing_example_message.jpg deleted file mode 100644 index 707f138876..0000000000 Binary files a/docusaurus/docs/Flutter/assets/location_sharing_example_message.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/location_sharing_example_message_thumbnail.jpg b/docusaurus/docs/Flutter/assets/location_sharing_example_message_thumbnail.jpg deleted file mode 100644 index e2b7d624f5..0000000000 Binary files a/docusaurus/docs/Flutter/assets/location_sharing_example_message_thumbnail.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/mac_os_split.png b/docusaurus/docs/Flutter/assets/mac_os_split.png deleted file mode 100644 index 7861d54c01..0000000000 Binary files a/docusaurus/docs/Flutter/assets/mac_os_split.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/message_actions.jpg b/docusaurus/docs/Flutter/assets/message_actions.jpg deleted file mode 100644 index dcfba64ec2..0000000000 Binary files a/docusaurus/docs/Flutter/assets/message_actions.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/message_input.png b/docusaurus/docs/Flutter/assets/message_input.png deleted file mode 100644 index d63cfbb3e2..0000000000 Binary files a/docusaurus/docs/Flutter/assets/message_input.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/message_input_change_position.png b/docusaurus/docs/Flutter/assets/message_input_change_position.png deleted file mode 100644 index 859107d25b..0000000000 Binary files a/docusaurus/docs/Flutter/assets/message_input_change_position.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/message_input_quoted_message.png b/docusaurus/docs/Flutter/assets/message_input_quoted_message.png deleted file mode 100644 index c1fda2237b..0000000000 Binary files a/docusaurus/docs/Flutter/assets/message_input_quoted_message.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/message_list_view.png b/docusaurus/docs/Flutter/assets/message_list_view.png deleted file mode 100644 index cc27be3c9b..0000000000 Binary files a/docusaurus/docs/Flutter/assets/message_list_view.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/message_list_view_pin.png b/docusaurus/docs/Flutter/assets/message_list_view_pin.png deleted file mode 100644 index 0b6f1c391f..0000000000 Binary files a/docusaurus/docs/Flutter/assets/message_list_view_pin.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/message_list_view_threads.png b/docusaurus/docs/Flutter/assets/message_list_view_threads.png deleted file mode 100644 index 2c9387663f..0000000000 Binary files a/docusaurus/docs/Flutter/assets/message_list_view_threads.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/message_reaction_theming.png b/docusaurus/docs/Flutter/assets/message_reaction_theming.png deleted file mode 100644 index 8cddd6ba22..0000000000 Binary files a/docusaurus/docs/Flutter/assets/message_reaction_theming.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/message_rounded_avatar.png b/docusaurus/docs/Flutter/assets/message_rounded_avatar.png deleted file mode 100644 index ec3733443a..0000000000 Binary files a/docusaurus/docs/Flutter/assets/message_rounded_avatar.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/message_search_list_view.png b/docusaurus/docs/Flutter/assets/message_search_list_view.png deleted file mode 100644 index b13f5bdc95..0000000000 Binary files a/docusaurus/docs/Flutter/assets/message_search_list_view.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/message_styles.png b/docusaurus/docs/Flutter/assets/message_styles.png deleted file mode 100644 index db04865c05..0000000000 Binary files a/docusaurus/docs/Flutter/assets/message_styles.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/message_theming.png b/docusaurus/docs/Flutter/assets/message_theming.png deleted file mode 100644 index b5d28dde0a..0000000000 Binary files a/docusaurus/docs/Flutter/assets/message_theming.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/message_widget_actions.png b/docusaurus/docs/Flutter/assets/message_widget_actions.png deleted file mode 100644 index e835a4ed04..0000000000 Binary files a/docusaurus/docs/Flutter/assets/message_widget_actions.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/sdk_title.png b/docusaurus/docs/Flutter/assets/sdk_title.png deleted file mode 100644 index 4d92e89142..0000000000 Binary files a/docusaurus/docs/Flutter/assets/sdk_title.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/server_key.png b/docusaurus/docs/Flutter/assets/server_key.png deleted file mode 100644 index f11d6fb56b..0000000000 Binary files a/docusaurus/docs/Flutter/assets/server_key.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/slidable_demo.jpg b/docusaurus/docs/Flutter/assets/slidable_demo.jpg deleted file mode 100644 index 4cbda5d738..0000000000 Binary files a/docusaurus/docs/Flutter/assets/slidable_demo.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/stream_chat_app_access_keys.jpg b/docusaurus/docs/Flutter/assets/stream_chat_app_access_keys.jpg deleted file mode 100644 index 1a869cc810..0000000000 Binary files a/docusaurus/docs/Flutter/assets/stream_chat_app_access_keys.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/stream_chat_user_database.jpg b/docusaurus/docs/Flutter/assets/stream_chat_user_database.jpg deleted file mode 100644 index fcfe73c82c..0000000000 Binary files a/docusaurus/docs/Flutter/assets/stream_chat_user_database.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/stream_firebase_extension_configuration.jpg b/docusaurus/docs/Flutter/assets/stream_firebase_extension_configuration.jpg deleted file mode 100644 index 0c2129319c..0000000000 Binary files a/docusaurus/docs/Flutter/assets/stream_firebase_extension_configuration.jpg and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/swipe_channel.png b/docusaurus/docs/Flutter/assets/swipe_channel.png deleted file mode 100644 index 44f13ca594..0000000000 Binary files a/docusaurus/docs/Flutter/assets/swipe_channel.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/user_list_view.png b/docusaurus/docs/Flutter/assets/user_list_view.png deleted file mode 100644 index 9aede8243d..0000000000 Binary files a/docusaurus/docs/Flutter/assets/user_list_view.png and /dev/null differ diff --git a/docusaurus/docs/Flutter/assets/using_theme.jpg b/docusaurus/docs/Flutter/assets/using_theme.jpg deleted file mode 100644 index b835d9316d..0000000000 Binary files a/docusaurus/docs/Flutter/assets/using_theme.jpg and /dev/null differ diff --git a/docusaurus/flutter-docusaurus-dontent-docs.plugin.js b/docusaurus/flutter-docusaurus-dontent-docs.plugin.js deleted file mode 100644 index ca348ab84c..0000000000 --- a/docusaurus/flutter-docusaurus-dontent-docs.plugin.js +++ /dev/null @@ -1,31 +0,0 @@ -module.exports = { - plugins: [ - [ - '@docusaurus/plugin-content-docs', - { - lastVersion: 'current', - versions: { - current: { - label: 'v8' - }, - '3.x.x': { - label: 'v3', - path: 'v3' - }, - '4.x.x': { - label: 'v4', - path: 'v4' - }, - '5.x.x': { - label: 'v5', - path: 'v5' - }, - '7.x.x': { - label: 'v7', - path: 'v7' - } - } - } - ] - ] -} diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/authentication_demo_app.jpg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/authentication_demo_app.jpg deleted file mode 100644 index eed57c3374..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/authentication_demo_app.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_header.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_header.png deleted file mode 100644 index 98f41c614b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_header.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_header_custom_title.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_header_custom_title.png deleted file mode 100644 index 65a9ee75a6..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_header_custom_title.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_list_header.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_list_header.png deleted file mode 100644 index 6f112db9be..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_list_header.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_list_header_custom_subtitle.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_list_header_custom_subtitle.png deleted file mode 100644 index 3c7798570a..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_list_header_custom_subtitle.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_list_view.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_list_view.png deleted file mode 100644 index a4390c2eac..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_preview.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_preview.png deleted file mode 100644 index 39f5629bb8..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/channel_preview.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/chat_basics.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/chat_basics.png deleted file mode 100644 index 82e27cfa49..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/chat_basics.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png deleted file mode 100644 index 9e92437dbf..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/dashboard_firebase_enable.jpeg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/dashboard_firebase_enable.jpeg deleted file mode 100644 index e4696ec882..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/dashboard_firebase_enable.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/dashboard_firebase_key.jpeg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/dashboard_firebase_key.jpeg deleted file mode 100644 index 87243e91f6..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/dashboard_firebase_key.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/dashboard_save_changes.jpeg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/dashboard_save_changes.jpeg deleted file mode 100644 index 1c58a93e63..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/dashboard_save_changes.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/end_to_end_encryption.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/end_to_end_encryption.png deleted file mode 100644 index b41e11ced6..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/end_to_end_encryption.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/firebase_authentication_dashboard.jpg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/firebase_authentication_dashboard.jpg deleted file mode 100644 index c304055768..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/firebase_authentication_dashboard.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png deleted file mode 100644 index c5670d0dc2..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/firebase_project_settings.jpeg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/firebase_project_settings.jpeg deleted file mode 100644 index 4fbc6521c3..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/firebase_project_settings.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/hashtag_example.jpg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/hashtag_example.jpg deleted file mode 100644 index a2bb3ba4c9..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/hashtag_example.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/live_stream_1.jpg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/live_stream_1.jpg deleted file mode 100644 index bef68c6edb..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/live_stream_1.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/live_stream_2.jpg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/live_stream_2.jpg deleted file mode 100644 index 02a3513297..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/live_stream_2.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/localization_support.jpg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/localization_support.jpg deleted file mode 100644 index 50d8b761ee..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/localization_support.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/location_sharing_example.jpg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/location_sharing_example.jpg deleted file mode 100644 index 7f220379c9..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/location_sharing_example.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/location_sharing_example_message.jpg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/location_sharing_example_message.jpg deleted file mode 100644 index 707f138876..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/location_sharing_example_message.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/location_sharing_example_message_thumbnail.jpg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/location_sharing_example_message_thumbnail.jpg deleted file mode 100644 index e2b7d624f5..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/location_sharing_example_message_thumbnail.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_actions.jpg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_actions.jpg deleted file mode 100644 index dcfba64ec2..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_actions.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_input.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_input.png deleted file mode 100644 index d63cfbb3e2..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_input.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_input_change_position.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_input_change_position.png deleted file mode 100644 index 859107d25b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_input_change_position.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_input_quoted_message.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_input_quoted_message.png deleted file mode 100644 index c1fda2237b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_input_quoted_message.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_list_view.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_list_view.png deleted file mode 100644 index cc27be3c9b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_list_view_pin.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_list_view_pin.png deleted file mode 100644 index 0b6f1c391f..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_list_view_pin.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_list_view_threads.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_list_view_threads.png deleted file mode 100644 index 2c9387663f..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_list_view_threads.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_reaction_theming.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_reaction_theming.png deleted file mode 100644 index 8cddd6ba22..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_reaction_theming.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_rounded_avatar.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_rounded_avatar.png deleted file mode 100644 index ec3733443a..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_rounded_avatar.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_search_list_view.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_search_list_view.png deleted file mode 100644 index b13f5bdc95..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_search_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_styles.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_styles.png deleted file mode 100644 index db04865c05..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_styles.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_theming.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_theming.png deleted file mode 100644 index b5d28dde0a..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_theming.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_widget_actions.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_widget_actions.png deleted file mode 100644 index e835a4ed04..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/message_widget_actions.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/sdk_title.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/sdk_title.png deleted file mode 100644 index 4d92e89142..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/sdk_title.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/server_key.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/server_key.png deleted file mode 100644 index f11d6fb56b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/server_key.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/stream_chat_user_database.jpg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/stream_chat_user_database.jpg deleted file mode 100644 index fcfe73c82c..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/stream_chat_user_database.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/swipe_channel.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/swipe_channel.png deleted file mode 100644 index 44f13ca594..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/swipe_channel.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/user_list_view.png b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/user_list_view.png deleted file mode 100644 index 9aede8243d..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/user_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/using_theme.jpg b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/using_theme.jpg deleted file mode 100644 index b835d9316d..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/assets/using_theme.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/basics/_category_.json b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/basics/_category_.json deleted file mode 100644 index 76d335692d..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/basics/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Introduction", - "position": 1 -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/basics/choose_package.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/basics/choose_package.mdx deleted file mode 100644 index b7ddf6a6ef..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/basics/choose_package.mdx +++ /dev/null @@ -1,54 +0,0 @@ ---- -id: choose_package -title: Choosing The Right Flutter Package ---- - -### Why the SDK is split into different packages - -Different applications need different levels of customization and integration with the Stream Chat SDK. -To do this, the Flutter SDK is split into three different packages which build upon the last and give -varying levels of control to the developer. The higher level packages offer better compatibility out of the -box while the lower level SDKs offer fine grained control. There is also a separate package for persistence -which allows you persist data locally which works with all packages. - -### How do I choose? - -#### The case for `stream_chat_flutter` - -For the quickest way to integrate Stream Chat with your app, the UI SDK (`stream_chat_flutter`) is the -way to go. `stream_chat_flutter` contains prebuilt components that manage most operations like data -fetching, pagination, sending a message, and more. This ensures you have a nearly out-of-the-box -experience adding chat to your applications. It is also possible to use this in conjunction with -lower level operations of the SDK to get the best of both worlds. - -:::note -The package allows customization of components to a large extent making it easy to tweak the theme -to match your app colors and such. If you require any additional feature or customization, feel free -to request this through our support channels. -::: - -Summary: - -For the quickest and easiest way to add Chat to your app with prebuilt UI components, use `stream_chat_flutter` - - -#### The case for `stream_chat_flutter_core` - -If your application involves UI that does not fit in with the `stream_chat_flutter` components, `stream_chat_flutter_core` -strips away the UI associated with the components and provides the data fetching and manipulation -capabilities while supplying builders for UI. This allows you to implement your own UI and themes -completely independently while not worrying about writing functions for data and pagination. - -Summary: - -For implementing your own custom UI while not having to worry about lower level API calls, use `stream_chat_flutter_core`. - -#### The case for `stream_chat` - -The `stream_chat` package is the Low-level Client (LLC) of Stream Chat in Flutter. This package wraps -the underlying functionality of Stream Chat and allows the most customization in terms of UI, data, -and architecture. - -Summary: - -For the most control over the SDK and dealing with low level calls to the API, use `stream_chat`. diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/basics/introduction.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/basics/introduction.mdx deleted file mode 100644 index 4f66dc67b9..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/basics/introduction.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -slug: / -id: introduction -title: About The Flutter SDK ---- -Exploring The Basics Of Stream Chat - -![](../assets/sdk_title.png) - -Stream Chat is a service that helps you easily build a full chat experience in your Flutter apps. -We also support a variety of other SDKs. - -This section of the documentation focuses on our Flutter SDK which helps you easily -ship high quality messaging experiences in apps and programs built with the [Flutter toolkit -made by Google](https://flutter.dev). - -The Stream Chat Flutter SDK comprises five different packages to choose from, ranging from ones -giving you complete control to ones that give you a rich out-of-the-box chat experience. - -The packages that make up the Stream Chat SDK are: - -1. Low Level Client (`stream_chat`): a pure Dart package that can be used on any Dart project. -It provides a low-level client to access the Stream Chat service. -2. Core (`stream_chat_flutter_core`): provides business logic to fetch common things required -for integrating Stream Chat into your application. -The core package allows more customisation and hence provides business logic but no UI components. -3. UI (`stream_chat_flutter`): this library includes both a low-level chat SDK and a set of -reusable and customizable UI components. -4. Persistence (`stream_chat_persistence`): provides a persistence client for fetching and -saving chat data locally. -5. Localizations (`stream_chat_localizations`): provides a set of localizations for the SDK. - -We recommend building prototypes using the full UI package, [`stream_chat_flutter`](https://pub.dev/packages/stream_chat_flutter), -since it contains UI widgets already integrated with Stream's API. It is the fastest way to get up -and running using Stream chat in your app. - -The Flutter SDK enables you to build any type of chat or messaging experience for Android, iOS, Web -and Desktop. - -If you're building a very custom UI and would prefer a more lean package, -[`stream_chat_flutter_core`](https://pub.dev/packages/stream_chat_flutter_core) will be suited to this -use case. Core allows you to build custom, expressive UIs while retaining the benefits of our full -Flutter SDK. APIs for accessing and controlling users, sending messages, and so forth are seamlessly integrated -into this package and accessible via providers and builders. - -Before going into the docs, let's take a small detour to look at how the elements of Stream Chat are structured. - -### Basic Structure - -There are two core elements in chat, Users and Channels. -Channels are groups of one or more users that can message each other. -In an app, you need to have a user connected to query channels. - -There is no specific distinction between a chat with only two people and a group chat, -but there is a way to create a unique chat between a certain number of people by creating a distinct channel. - -![](../assets/chat_basics.png) - -In essence, a normal two-person chat would be a distinct channel created with two members (you cannot add or delete members in this channel), whereas a group created with two people would simply be a non distinct channel (possible to add or remove members). - -:::note -It is also possible to add more than two people in a distinct channel which retains the same add/removal properties and resembles the Slack DMs where you can DM one or more people as well. -::: - -In summary, if you were creating a Whatsapp-like app, the first screen would be a list of channels - which on opening would show a list of messages that were sent by the users in the Channel. - -While this is a simplistic overview of the service, the Flutter SDK handles the UI and more time consuming things (media upload, offline storage, theming, etc.) for you. - -Before reading the docs, consider trying our [online API tour](https://getstream.io/chat/get_started/), -it is a nice way to learn how the API works. -It's in-browser so you'll need to use JavaScript but the core concepts are pretty much the same as Dart. - -You may also like to look at the [Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) -which focuses on using the UI package to get Stream Chat integrated into a Flutter app. - -Further sections break down each individual packages and explain several common operations. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/basics/versioning_policy.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/basics/versioning_policy.mdx deleted file mode 100644 index 9f50c98f9e..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/basics/versioning_policy.mdx +++ /dev/null @@ -1,19 +0,0 @@ ---- -id: versioning_policy -title: Versioning Policy ---- - -All of the Stream Chat packages follow [semantic versioning](https://semver.org/). - -That means that with a version number x.y.z (major.minor.patch): -- When releasing bug fixes (backwards compatible), we make a patch release by changing the z number (ex: 3.6.2 to 3.6.3). A bug fix is defined as an internal change that fixes incorrect behavior. -- When releasing new features or non-critical fixes, we make a minor release by changing the y number (ex: 3.6.2 to 3.7.0). -- When releasing breaking changes (backward incompatible), we make a major release by changing the x number (ex: 3.6.2 to 4.0.0). - -See the [semantic versioning](https://dart.dev/tools/pub/versioning#semantic-versions) section from the Dart docs for more information. - -This versioning policy does not apply to prerelease packages (below major version of 1). See this -[StackOverflow thread](https://stackoverflow.com/questions/66201337/how-do-dart-package-versions-work-how-should-i-version-my-flutter-plugins) -for more information on Dart package versioning. - -Whenever possible, we will add deprecation warnings in preparation for future breaking changes. diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/_category_.json b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/_category_.json deleted file mode 100644 index cb58ac0dc4..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Guides", - "position": 2 -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_chat_to_video_livestreams.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_chat_to_video_livestreams.mdx deleted file mode 100644 index 8d437082a8..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_chat_to_video_livestreams.mdx +++ /dev/null @@ -1,92 +0,0 @@ ---- -id: adding_chat_to_video_livestreams -title: Adding Chat To Video Livestreams ---- - -Adding Chat To Video Livestreams - -### Introduction - -Video livestreams are usually complemented with a chat section to make the livestream more interactive -and encourage retention. There are several ways to show the chat interface on the screen and requires -some design choices. - -This guide details multiple ways of adding chat functionality to your video livestream. - -### Implementing Chat - -There are two common scenarios in live-streaming applications depending how well integrated the two -components (video + chat) are allowed to be on the screen. Two common types are split-screen and a -chat overlay that fades in. - -Let's explore creating both types: - -### Split-screen - -In the split-screen implementation, we have a visual split between the video and the message list. -This allows the content to be unobstructed by chat and have a clear separation of boundaries. - -![](../assets/live_stream_1.jpg) - -```dart -Scaffold( - body: Column( - children: [ - Expanded( - child: // Your video implementation here, - ), - Expanded( - child: Column( - children: [ - Expanded( - child: MessageListView(), - ), - MessageInput(), - ], - ), - ), - ], - ), -) -``` - -### Overlapping chat with a transparency gradient - -Another way to add chat is to overlay the video content with messages which progressively fade out -as we go to the top of the screen. This gives the content a more rich feel as it takes the whole -screen and allows the chat to be more homogeneously integrated with the content. - -The second type looks like this: - -![](../assets/live_stream_2.jpg) - -We can use a `Stack` for achieving this: - -```dart -Scaffold( - body: Stack( - children: [ - // Add your video implementation here - ShaderMask( - shaderCallback: (rect) { - return LinearGradient( - begin: Alignment.bottomCenter, - end: Alignment.topCenter, - colors: [Colors.black, Colors.transparent], - stops: [0.4, 0.65] - ).createShader(Rect.fromLTRB(0, 0, rect.width, rect.height)); - }, - blendMode: BlendMode.dstIn, - child: Column( - children: [ - Expanded( - child: MessageListView(), - ), - MessageInput(), - ], - ), - ), - ], - ), - ) -``` diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_custom_attachments.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_custom_attachments.mdx deleted file mode 100644 index 961ef1a1c2..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_custom_attachments.mdx +++ /dev/null @@ -1,263 +0,0 @@ ---- -id: adding_custom_attachments -title: Adding Custom Attachments ---- - -Adding Your Own Types Of Attachments To A Message - -### Introduction - -Stream Chat supports attachment types like images, video and files by default. You can also add your -own types of attachments through the SDK such as location, audio, etc. - -This involves doing three things: - -1) Rendering the attachment thumbnail in the `MessageInput` - -2) Sending a message with the custom attachment - -3) Rendering the custom message attachment - -To do this, let's check out an example to add location sharing to Stream Chat. - -### Location Sharing - -Let's build an example of location sharing option in the app: - -![](../assets/location_sharing_example.jpg) - -* Show a "Share Location" button next to MessageInput `Textfield`. - -* When the user presses this button, it should fetch the current location coordinates of the user, and send a message on the channel as follows: - -```dart -Message( - text: 'This is my location', - attachments: [ - Attachment( - uploadState: UploadState.success(), - type: 'location', - extraData: { - 'latitude': 'fetched_latitude', - 'longitude': 'fetched_longitude', - }, - ), - ], -) -``` - -For our example, we are going to use [`geolocator`](https://pub.dev/packages/geolocator) library. -Please check their [setup instructions](https://pub.dev/packages/geolocator) on their docs. - -NOTE: If you are testing on iOS simulator, you will need to set some dummy coordinates, as mentioned [here](https://stackoverflow.com/a/31238119/7489541). -Also don't forget to enable "location update" capability in background mode, from XCode. - -On the receiver end, `location` type attachment should be rendered in map view, in the `MessageListView`. -We are going to use [Google Static Maps API](https://developers.google.com/maps/documentation/maps-static/overview) to render the map in the message. -You can use other libraries as well such as [`google_maps_flutter`](https://pub.dev/packages/google_maps_flutter). - -First, we add a button which when clicked fetches and shares location into the `MessageInput`: - -```dart -MessageInput( - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20.0, - color: StreamChatTheme.of(context).colorTheme.grey, - ), - onTap: () { - var channel = StreamChannel.of(context).channel; - var user = StreamChat.of(context).user; - - _determinePosition().then((value) { - channel.sendMessage( - Message( - text: 'This is my location', - attachments: [ - Attachment( - uploadState: UploadState.success(), - type: 'location', - extraData: { - 'latitude': value.latitude.toString(), - 'longitude': value.longitude.toString(), - }, - ), - ], - ), - ); - }).catchError((err) { - print('Error getting location!'); - }); - }, - ), - ], -), - -Future _determinePosition() async { - bool serviceEnabled; - LocationPermission permission; - - serviceEnabled = await Geolocator.isLocationServiceEnabled(); - if (!serviceEnabled) { - return Future.error('Location services are disabled.'); - } - - permission = await Geolocator.checkPermission(); - if (permission == LocationPermission.denied) { - permission = await Geolocator.requestPermission(); - if (permission == LocationPermission.deniedForever) { - return Future.error( - 'Location permissions are permanently denied, we cannot request permissions.'); - } - - if (permission == LocationPermission.denied) { - return Future.error( - 'Location permissions are denied'); - } - } - - return await Geolocator.getCurrentPosition(); -} -``` - -Next, we build the Static Maps URL (Add your API key before using the code snippet): - -```dart - String _buildMapAttachment(String lat, String long) { - var baseURL = 'https://maps.googleapis.com/maps/api/staticmap?'; - var url = Uri( - scheme: 'https', - host: 'maps.googleapis.com', - port: 443, - path: '/maps/api/staticmap', - queryParameters: { - 'center': '${lat},${long}', - 'zoom': '15', - 'size': '600x300', - 'maptype': 'roadmap', - 'key': 'YOUR_API_KEY', - 'markers': 'color:red|${lat},${long}' - }); - - return url.toString(); - } -``` - -And then modify the `MessageListView` and tell it how to build a location attachment, using the `messageBuilder` property and copying the default message implementation overriding the `customAttachmentBuilders` property: - -```dart -MessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - customAttachmentBuilders: { - 'location': (context, message, attachments) { - final attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'], - attachments[0].extraData['longitude'], - ), - ); - - return wrapAttachmentWidget(context, attachmentWidget, null, true, BorderRadius.circular(8.0)); - } - }, - ); - }, -), -``` - -This gives us the final location attachment: - -![](../assets/location_sharing_example_message.jpg) - -Additionally, you can also add a thumbnail if a message has a location attachment (unlike in this case, where we sent the message directly). - -To do this, we will: - -1) Add an attachment instead of sending a message - -2) Customize the `MessageInput` - -First, we add the attachment when the location button is clicked: - -```dart - GlobalKey _messageInputKey = GlobalKey(); - - MessageInput( - key: _messageInputKey, - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20.0, - color: StreamChatTheme.of(context).colorTheme.grey, - ), - onTap: () { - _determinePosition().then((value) { - _messageInputKey.currentState.addAttachment( - Attachment( - uploadState: UploadState.success(), - type: 'location', - extraData: { - 'latitude': value.latitude.toString(), - 'longitude': value.longitude.toString(), - }, - ), - ); - }).catchError((err) { - print('Error getting location!'); - }); - }, - ), - ], - ), -``` - -After this, we can build the thumbnail: - -```dart -MessageInput( - key: _messageInputKey, - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20.0, - color: StreamChatTheme.of(context).colorTheme.grey, - ), - onTap: () { - _determinePosition().then((value) { - _messageInputKey.currentState.addAttachment( - Attachment( - uploadState: UploadState.success(), - type: 'location', - extraData: { - 'latitude': value.latitude.toString(), - 'longitude': value.longitude.toString(), - }, - ), - ); - }).catchError((err) { - print('Error getting location!'); - }); - }, - ), - ], - attachmentThumbnailBuilders: { - 'location': (context, attachment) { - return Image.network( - _buildMapAttachment( - attachment.extraData['latitude'], - attachment.extraData['longitude'], - ), - ); - }, - }, -), -``` - -And we can see the thumbnails in the MessageInput: - -![](../assets/location_sharing_example_message_thumbnail.jpg) diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_local_data_persistence.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_local_data_persistence.mdx deleted file mode 100644 index e9b4909b17..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_local_data_persistence.mdx +++ /dev/null @@ -1,75 +0,0 @@ ---- -id: adding_local_data_persistence -title: Adding Local Data Persistence ---- - -Adding Local Data Persistence - -### Introduction - -Most messaging apps need to work regardless of whether the app is currently connected to the internet. -Local data persistence stores the fetched data from the backend on a local SQLite database using the -moor package in Flutter. All packages in the SDK can use local data persistence to store messages -across multiple platforms. - -### Implementation - -To add data persistence you can extend the class ChatPersistenceClient and pass an instance to the StreamChatClient. - -```dart -class CustomChatPersistentClient extends ChatPersistenceClient { -... -} - -final client = StreamChatClient( - apiKey ?? kDefaultStreamApiKey, - logLevel: Level.INFO, -)..chatPersistenceClient = CustomChatPersistentClient(); -``` - -We provide an official persistent client in the [`stream_chat_persistence`](https://pub.dev/packages/stream_chat_persistence) -package that works using the library [moor](https://moor.simonbinder.eu), an SQLite ORM. - -Add this to your package's `pubspec.yaml` file, using the latest version. - -```yaml -dependencies: - stream_chat_persistence: ^latest_version -``` - -You should then run `flutter packages get` - -The usage is pretty simple. - -1. Create a new instance of `StreamChatPersistenceClient` providing `logLevel` and `connectionMode` - -```dart -final chatPersistentClient = StreamChatPersistenceClient( - logLevel: Level.INFO, - connectionMode: ConnectionMode.background, -); -``` - -2. Pass the instance to the official `StreamChatClient` - -```dart - final client = StreamChatClient( - apiKey ?? kDefaultStreamApiKey, - logLevel: Level.INFO, - )..chatPersistenceClient = chatPersistentClient; -``` - -And you are ready to go... - -Note that passing `ConnectionMode.background` the database uses a background isolate to unblock the main thread. -The `StreamChatClient` uses the `chatPersistentClient` to synchronize the database with the newest -information every time it receives new data about channels/messages/users. - -### Multi-user - -The DB file is named after the `userId`, so if you instantiate a client using a different `userId` you will use a different database. -Calling `client.disconnectUser(flushChatPersistence: true)` flushes all current database data. - -### Updating/deleting/sending a message while offline - -The information about the action is saved in offline storage. When the client returns online, everything is retried. diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_localization.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_localization.mdx deleted file mode 100644 index 065d25c60b..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_localization.mdx +++ /dev/null @@ -1,194 +0,0 @@ ---- -id: adding_localization -title: Adding Localization (l10n) / Internationalization (i18n) ---- - -Adding Localization To UI Widgets - -### Introduction - -We have a dedicated package for adding localization to our UI widgets. It's called `stream_chat_localizations` and you can find it [here](https://pub.dev/packages/stream_chat_localizations). - -![](../assets/localization_support.jpg) - -## What is Localization? - -If you deploy your app to users who speak another language, you'll need to internationalize (localize) it. That means you need to write the app in a way that makes it possible to localize values like text and layouts for each language or locale that the app supports. For more information, see the [Flutter documentation](https://flutter.dev/docs/development/accessibility-and-localization/internationalization). - -What this package allows you to do is to provide localized strings for the Stream chat widgets. For example, depending on the application locale, the Stream Chat widgets will display the appropriate language. The locale will be set automatically, based on system preferences, or you could set it programmatically in your app. The package supports several different languages, with more to be added. The package allows you to override any supported language or add a new language that isn't supported. - -:::note -If you want to translate messages, or enable automatic translation, please see the [Translation documentation](https://getstream.io/chat/docs/flutter-dart/translation/?language=dart). -::: - -### Supported languages - -At the moment we support the following languages: -- [English](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart) -- [Hindi](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart) -- [Italian](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart) -- [French](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart) -- [Spanish](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart) -- [Japanese](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart) -- [Korean](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart) -- [Portuguese](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_pt.dart) -- [German](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_de.dart) - - -More languages will be added in the future. Feel free to [contribute](https://github.com/GetStream/stream-chat-flutter/blob/master/CONTRIBUTING.md) to add more languages. - -### Add dependency - -Add this to your package's `pubspec.yaml` file, use the latest version [![Pub](https://img.shields.io/pub/v/stream_chat_localizations.svg)](https://pub.dartlang.org/packages/stream_chat_localizations) -```yaml -dependencies: - stream_chat_localizations: ^latest_version -``` - -Then run `flutter packages get` - -### Usage - -Generally, Flutter and the Stream Chat SDK will use the system locale of the user's device, if that locale is supported (see below). If the locale is not supported we will default to `en` (however it's always possible to [customize that](#changing-the-default-language)). -Make sure to read more about localization in the [official Flutter docs](https://flutter.dev/docs/development/accessibility-and-localization/internationalization). - -```dart -import 'package:flutter/material.dart'; -import 'package:stream_chat_localizations/stream_chat_localizations.dart'; - -void main() { - WidgetsFlutterBinding.ensureInitialized(); - runApp(MyApp()); -} - -class MyApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - return MaterialApp( - // Add all the supported locales - supportedLocales: const [ - Locale('en'), - Locale('hi'), - Locale('fr'), - Locale('it'), - Locale('es'), - Locale('ja'), - Locale('ko'), - ], - // Add GlobalStreamChatLocalizations.delegates - localizationsDelegates: GlobalStreamChatLocalizations.delegates, - builder: (context, widget) => StreamChat( - client: client, - child: widget, - ), - home: StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ); - } -} -``` - -## Setting a language -The application language can be changed through system preferences or programmatically. - -### System Preferences -The application locale can be changed by changing the language for your device or emulator within the device's system preferences. - -[iOS change language](https://support.apple.com/en-us/HT204031) - -[Android change language](https://support.google.com/websearch/answer/3333234?co=GENIE.Platform%3DAndroid&hl=en) - -Note that the language needs to be supported in your application to work. - -### Programmatically -You can also set the locale programmatically in your Flutter application without changing the device's language. - -```dart -return MaterialApp( - ... - locale: const Locale('fr'), - ... -); -``` - -There are many ways that this can be set for additional control. For information and examples, see this [Stack Overflow post](https://stackoverflow.com/questions/49441212/flutter-multi-lingual-application-how-to-override-the-locale). - -### Adding a new language - -To add a new language, create a new class extending `GlobalStreamChatLocalizations` and create a delegate for it, adding it to the `delegates` array. - -Check out [this example](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/example/lib/add_new_lang.dart) to see how to add a new language. - -### Override existing languages - -To override an existing language, create a new class extending that particular language class and create a delegate for it, adding it to the `delegates` array. - -Check out [this example](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/example/lib/override_lang.dart) to see how to override an existing language. - -### Changing the default language - -To change the default language you can use the `MaterialApp.localeListResolutionCallback` property. -Here is an example of how that would look like: - -```dart - MaterialApp( - theme: ThemeData.light(), - darkTheme: ThemeData.dark(), - // Add all the supported locales - supportedLocales: const [ - Locale('en'), - Locale('hi'), - Locale('fr'), - Locale('it'), - Locale('es'), - Locale('ja'), - Locale('ko'), - ], - // locales are the locales of the device - // supportedLocales are the app supported locales - localeListResolutionCallback: (locales, supportedLocales) { - // We map the supported locales to language codes - // note that this is completely optional and this logic can be changed as you like - final supportedLanguageCodes = - supportedLocales.map((e) => e.languageCode); - if (locales != null) { - // we iterate over the locales and find the first one that is supported - for (final locale in locales) { - if (supportedLanguageCodes.contains(locale.languageCode)) { - return locale; - } - } - } - - // if we didn't find a supported language, we return the Italian language - return const Locale('it'); - }, - // Add GlobalStreamChatLocalizations.delegates - localizationsDelegates: GlobalStreamChatLocalizations.delegates, - ... - -``` - -In this case, we're using Italian as the default language. - -### ⚠️ Note on **iOS** - -For translation to work on **iOS** you need to add supported locales to -`ios/Runner/Info.plist` as described [here](https://flutter.dev/docs/development/accessibility-and-localization/internationalization#specifying-supportedlocales). - -Example: - -```xml -CFBundleLocalizations - - en - nb - fr - it - es - ja - ko - -``` diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_push_notifications.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_push_notifications.mdx deleted file mode 100644 index fa72779b9d..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_push_notifications.mdx +++ /dev/null @@ -1,262 +0,0 @@ ---- -id: adding_push_notifications -title: Adding Push Notifications (V1 legacy) ---- - -Adding Push Notifications To Your Application - -:::note -Version 1 (legacy) of push notifications won't be removed immediately but there won't be any new features. That's why new applications are highly recommended to use version 2 from the beginning to leverage upcoming new features. -::: - -### Introduction - -Push notifications are a core part of the experience for a messaging app. Users often need to be notified -of new messages and old notifications sometimes need to be updated silently as well. - -This guide details how to add push notifications to your app. - -Make sure to check [this section](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart) of the docs to read about the push delivery logic. - -### Setup FCM - -To integrate push notifications in your Flutter app you need to use the package [`firebase_messaging`](https://pub.dev/packages/firebase_messaging). - - -Follow the [Firebase documentation](https://firebase.flutter.dev/docs/messaging/overview/) to know how to set up the plugin for both Android and iOS. - - -Once that's done FCM should be able to send push notifications to your devices. - -### Integration with Stream - -#### Step 1 - -From the [Firebase Console](https://console.firebase.google.com/), select the project your app belongs to. - -#### Step 2 - -Click on the gear icon next to `Project Overview` and navigate to **Project settings** - -![](../assets/firebase_project_settings.jpeg) - -#### Step 3 - -Navigate to the `Cloud Messaging` tab - -#### Step 4 - -Under `Project Credentials`, locate the `Server key` and copy it - -![](../assets/server_key.png) - -#### Step 5 - -Upload the `Server Key` in your chat dashboard - -![](../assets/dashboard_firebase_enable.jpeg) - -![](../assets/dashboard_firebase_key.jpeg) - - -:::note -We are setting up the Android section, but this will work for both Android and iOS if you're using Firebase for both of them. -::: - -#### Step 6 - -Save your push notification settings changes - -![](../assets/dashboard_save_changes.jpeg) - -**OR** - -Upload the `Server Key` via API call using a backend SDK - -```js -await client.updateAppSettings({ - firebase_config: { - server_key: 'server_key', - notification_template: `{"message":{"notification":{"title":"New messages","body":"You have {{ unread_count }} new message(s) from {{ sender.name }}"},"android":{"ttl":"86400s","notification":{"click_action":"OPEN_ACTIVITY_1"}}}}`, - data_template: `{"sender":"{{ sender.id }}","channel":{"type": "{{ channel.type }}","id":"{{ channel.id }}"},"message":"{{ message.id }}"}` - }, -}); -``` - -### Registering a device at Stream Backend - -Once you configure Firebase server key and set it up on Stream dashboard a device that is supposed to receive push notifications needs to be registered at Stream backend. This is usually done by listening for Firebase device token updates and passing them to the backend as follows: - -```dart -firebaseMessaging.onTokenRefresh.listen((token) { - client.addDevice(token, PushProvider.firebase); -}); -``` - -### Possible issues - - -We only send push notifications when the user doesn't have any active web socket connection (which is established when you call `client.connectUser`). If you set the [onBackgroundEventReceived](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/onBackgroundEventReceived.html) property of the StreamChat widget, when your app goes to background, your device will keep the WS connection alive for 1 minute, and so within this period, you won't receive any push notification. - -Make sure to read the [general push docs](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart) in order to avoid known gotchas that may make your relationship with notifications go bad 😢 - -### Testing if Push Notifications are Setup Correctly - -If you're not sure if you've set up push notifications correctly (for example you don't always receive them, they work unreliably), you can follow these steps to make sure your configuration is correct and working: - -1. Clone our repository for push testing git clone git@github.com:GetStream/chat-push-test.git - -2. `cd flutter` - -3. In folder run `flutter pub get` - -4. Input your API key and secret in `lib/main.dart` - -5. Change the bundle identifier/application ID and development team/user so you can run the app in your device (**do not** run on iOS simulator, Android emulator is fine) - -6. Add your `google-services.json/GoogleService-Info.plist` - -7. Run the app - -8. Accept push notification permission (iOS only) - -9. Tap on `Device ID` and copy it - -10. Send the app to background - -11. After configuring [stream-cli](https://github.com/GetStream/stream-cli) paste the following command on command line using your user ID - -```shell -stream chat:push:test -u -``` - -You should get a test push notification - -### App in the background but still connected - -The [StreamChat](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat-class.html) widget lets you define a [onBackgroundEventReceived](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/onBackgroundEventReceived.html) handler in order to handle events while the app is in the background, but the client is still connected. - -This is useful because it lets you keep the connection alive in cases in which the app goes in the background just for some seconds (for example multitasking, picking pictures from the gallery...) - -You can even customize the [backgroundKeepAlive](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/backgroundKeepAlive.html) duration. - -In order to show notifications in such a case we suggest using the package [`flutter_local_notifications`](https://pub.dev/packages/flutter_local_notifications); follow the package guide to successfully set up the plugin. - -Once that's done you should set the [onBackgroundEventReceived](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/onBackgroundEventReceived.html); here is an example: - -```dart -... -StreamChat( - client: client, - onBackgroundEventReceived: (e) { - final currentUserId = client.state.user.id; - if (![ - EventType.messageNew, - EventType.notificationMessageNew, - ].contains(event.type) || - event.user.id == currentUserId) { - return; - } - if (event.message == null) return; - final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); - final initializationSettingsAndroid = - AndroidInitializationSettings('launch_background'); - final initializationSettingsIOS = IOSInitializationSettings(); - final initializationSettings = InitializationSettings( - android: initializationSettingsAndroid, - iOS: initializationSettingsIOS, - ); - await flutterLocalNotificationsPlugin.initialize(initializationSettings); - await flutterLocalNotificationsPlugin.show( - event.message.id.hashCode, - event.message.user.name, - event.message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'message channel', - 'Message channel', - 'Channel used for showing messages', - priority: Priority.high, - importance: Importance.high, - ), - iOS: IOSNotificationDetails(), - ), - ); - }, - child: .... -); -... -``` - -As you can see we generate a local notification whenever a message.new or notification.message_new event is received. - -### Foreground notifications - -Sometimes you may want to show a notification when the app is in the foreground. -For example, when you're in a channel and you receive a new message from someone in another channel. - -For this scenario, you can also use the `flutter_local_notifications` package to show a notification. - -You need to listen for new events using `StreamChatClient.on` and handle them accordingly. - -Here we're checking if the event is a `message.new` or `notification.message_new` event, and if the message is from a different user than the current user. In that case we'll show a notification. - -```dart -client.on( - EventType.messageNew, - EventType.notificationMessageNew, -).listen((event) { - if (event.message?.user?.id == client.state.currentUser?.id) { - return; - } - showLocalNotification(event, client.state.currentUser!.id, context); -}); -``` - -:::note -You should also check that the channel of the message is different than the channel in the foreground. -How you do this depends on your app infrastructure and how you handle navigation. -Take a look at the [Stream Chat v1 sample app](https://github.com/GetStream/flutter-samples/blob/main/packages/stream_chat_v1/lib/home_page.dart#L11) to see how we're doing it over there. -::: - -### Saving notification messages to the offline storage - -You may want to save received messages when you receive them via a notification so that later on when you open the app they're already there. - -To do this we need to update the push notification data payload at Stream Dashboard and clear the notification one: - -```json -{ - "message_id": "{{ message.id }}", - "channel_id": "{{ channel.id }}", - "channel_type": "{{ channel.type }}" -} -``` - -Then we need to integrate the package [`stream_chat_persistence`](https://pub.dev/packages/stream_chat_persistence) in our app that exports a persistence client, learn [here](https://pub.dev/packages/stream_chat_persistence#usage) how to set it up. - -Then during the call `firebaseMessaging.configure(...)` we need to set the `onBackgroundMessage` parameter using a TOP-LEVEL or STATIC function to handle background messages; here is an example: - -```dart -Future myBackgroundMessageHandler(message) async { - if (message.containsKey('data')) { - final data = message['data']; - final messageId = data['message_id']; - final channelId = data['channel_id']; - final channelType = data['channel_type']; - final cid = '$channelType:$channelId'; - - final client = StreamChatClient(apiKey); - final persistenceClient = StreamChatPersistenceClient(); - await persistenceClient.connect(userId); - - final message = await client.getMessage(messageId).then((res) => res.message); - - await persistenceClient.updateMessages(cid, [message]); - persistenceClient.disconnect(); - - /// This can be done using the package flutter_local_notifications as we did before 👆 - _showLocalNotification(); - } -} -``` diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_push_notifications_v2.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_push_notifications_v2.mdx deleted file mode 100644 index 1cccc5fd66..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/adding_push_notifications_v2.mdx +++ /dev/null @@ -1,300 +0,0 @@ ---- -id: adding_push_notifications_v2 -title: Adding Push Notifications (V2) ---- - -Adding Push Notifications To Your Application - -### Introduction - -Push notifications are a core part of the experience for a messaging app. Users often need to be notified -of new messages and old notifications sometimes need to be updated silently. - -This guide details how to add push notifications to your app. - -You can read more about Stream’s [push delivery logic](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart#push-delivery-rules). - -### Setup FCM - -To integrate push notifications in your Flutter app, you need to use the package [`firebase_messaging`](https://pub.dev/packages/firebase_messaging). - - -Follow the [Firebase documentation](https://firebase.flutter.dev/docs/messaging/overview/) to set up the plugin for Android and iOS. - - -Once that's done, FCM should be able to send push notifications to your devices. - -### Integration With Stream - -#### Step 1 - Get the Firebase Credentials - -These credentials are the [private key file](https://firebase.google.com/docs/admin/setup#:~:text=To%20generate%20a%20private%20key%20file%20for%20your%20service%20account%3A) 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 which needs to be uploaded to Stream’s server as explained in next step. - -#### Step 2 - Upload the Firebase Credentials to Stream - -You can upload your Firebase credentials using either the dashboard or the app settings API (available only in backend SDKs). - -##### Using the Stream Dashboard - -1. Go to the **Chat Overview** page on Stream Dashboard - -![](../assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png) - -2. Enable **Firebase Notification** toggle on **Chat Overview** - -![](../assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png) - -3. Enter your Firebase Credentials and press `"Save"`. - -##### Using the API - -You can also enable Firebase notifications and upload the Firebase credentials using one of our server SDKs. - -For example, using the JavaScript SDK: - -```js -const client = StreamChat.getInstance('api_key', 'api_secret'); -client.updateAppSettings({ - push_config: { - version: 'v2' - }, - firebase_config: { - credentials_json: fs.readFileSync( - './firebase-credentials.json', - 'utf-8', - ), - }); -``` -### Registering a Device With Stream Backend - -Once you configure a Firebase server key and set it up on Stream dashboard then a device that is supposed to receive push notifications needs to be registered on the Stream backend. This is usually done by listening for Firebase device token updates and passing them to the backend as follows: - -```dart -firebaseMessaging.onTokenRefresh.listen((token) { - client.addDevice(token, PushProvider.firebase); -}); -``` - -### Receiving Notifications - -Push notifications behave a bit differently depending on whether you are using iOS or Android. -See [here](https://firebase.flutter.dev/docs/messaging/usage#message-types) to understand the difference between **notification** and **data** payloads. - -#### iOS - -On iOS we send both a **notification** and a **data** payload. -This means you don't need to do anything special to get the notification to show up. However, you might want to handle the data payload to perform some logic when the user taps on the notification. - -To update the template, you can use a backend SDK. -For example, using the JavaScript SDK: - -```js -const client = StreamChat.getInstance(‘api_key’, ‘api_secret’); -const apn_template = `{ - "aps": { - "alert": { - "title": "New message from {{ sender.name }}", - "body": "{{ truncate message.text 2000 }}" - }, - "mutable-content": 1, - "category": "stream.chat" - }, - "stream": { - "sender": "stream.chat", - "type": "message.new", - "version": "v2", - "id": "{{ message.id }}", - "cid": "{{ channel.cid }}" - } -}`; - -client.updateAppSettings({ - firebase_config: { - apn_template, - }); -``` - -#### Android -On Android we send only a **data** payload. This gives you more flexibility and lets you decide what to do with the notification. - -For example, you can listen and generate a notification from them. - -To generate a notification when a **data-only** message is received and the app is in background: - -```dart -Future onBackgroundMessage(RemoteMessage message) async { - final chatClient = StreamChatClient(apiKey); - - chatClient.connectUser( - User(id: userId), - userToken, - connectWebSocket: false, - ); - - handleNotification(message, chatClient); -} - -void handleNotification( - RemoteMessage message, - StreamChatClient chatClient, -) async { - - final data = message.data; - - if (data['type'] == 'message.new') { - final flutterLocalNotificationsPlugin = await setupLocalNotifications(); - final messageId = data['id']; - final response = await chatClient.getMessage(messageId); - - flutterLocalNotificationsPlugin.show( - 1, - 'New message from ${response.message.user.name} in ${response.channel.name}', - response.message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'new_message', - 'New message notifications channel', - )), - ); - } -} - -FirebaseMessaging.onBackgroundMessage(onBackgroundMessage); -``` - -In the above example, you get the message details using the `getMessage` method and then you use the [`flutter_local_notifications`](https://pub.dev/packages/flutter_local_notifications) package to show the actual notification. - -##### Using a Template on Android - -It's still possible to add a **notification** payload to Android notifications. -You can do so by adding a template using a backend SDK. -For example, using the JavaScript SDK: - -```js -const client = StreamChat.getInstance(‘api_key’, ‘api_secret’); -const notification_template = ` -{ - "title": "{{ sender.name }} @ {{ channel.name }}", - "body": "{{ message.text }}", - "click_action": "OPEN_ACTIVITY_1", - "sound": "default" -}`; - -client.updateAppSettings({ - firebase_config: { - notification_template, - }); -``` - -### Possible Issues - -Make sure to read the [general push notification docs](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart) in order to avoid known gotchas that may make your relationship with notifications difficult 😢. - -### Testing if Push Notifications are Setup Correctly - -If you're not sure whether you've set up push notifications correctly, for example, you don't always receive them, or they don’t work reliably, then you can follow these steps to make sure your configuration is correct and working: -1. Clone our repository for push testing: `git clone git@github.com:GetStream/chat-push-test.git` -2. `cd flutter` -3. In that folder run `flutter pub get` -4. Input your API key and secret in `lib/main.dart` -5. Change the bundle identifier/application ID and development team/user so you can run the app on your physical device.**Do not** run on an iOS simulator, as it will not work. Testing on an Android emulator is fine. -6. Add your `google-services.json/GoogleService-Info.plist` -7. Run the app -8. Accept push notification permission (iOS only) -9. Tap on `Device ID` and copy it -11. After configuring [stream-cli](https://github.com/GetStream/stream-cli), run the following command using your user ID: -```shell -stream chat:push:test -u -``` - -You should get a test push notification 🥳 - - -### Foreground Notifications - -Sometimes you may want to show a notification when the app is in the foreground. -For example, when you're in a channel and you receive a new message from someone in another channel. - -For this scenario, you can also use the `flutter_local_notifications` package to show a notification. - -You need to listen for new events using `FirebaseMessaging.onMessage.listen()` and handle them accordingly: - -```dart -FirebaseMessaging.onMessage.listen((message) async { - handleNotification( - message, - chatClient, - ); -}); -``` - -:::note -You should also check that the channel of the message is different than the channel in the foreground. -How you do this depends on your app infrastructure and how you handle navigation. -Take a look at the [Stream Chat v1 sample app](https://github.com/GetStream/flutter-samples/blob/main/packages/stream_chat_v1/lib/home_page.dart#L11) to see how we're doing it over there. -::: - -### Saving Notification Messages to the Offline Storage (Only Android) - -When the app is closed you may want to save received messages when you receive them via a notification so that later on when you open the app they're already there. - -To do this you need to integrate the package [`stream_chat_persistence`](https://pub.dev/packages/stream_chat_persistence) in our app that exports a persistence client, see [here](https://pub.dev/packages/stream_chat_persistence#usage) how to set it up. - -Then calling `FirebaseMessaging.onBackgroundMessage(...)` you need to use a TOP-LEVEL or STATIC function to handle background messages; here is an example: - -```dart -Future onBackgroundMessage(RemoteMessage message) async { - final chatClient = StreamChatClient(apiKey); - final persistenceClient = StreamChatPersistenceClient(); - - await persistenceClient.connect(userId); - - chatClient.connectUser( - User(id: userId), - userToken, - connectWebSocket: false, - ); - - handleNotification(message, chatClient); -} - -void handleNotification( - RemoteMessage message, - StreamChatClient chatClient, -) async { - final data = message.data; - if (data['type'] == 'message.new') { - final flutterLocalNotificationsPlugin = await setupLocalNotifications(); - final messageId = data['id']; - final cid = data['cid']; - final response = await chatClient.getMessage(messageId); - await persistenceClient.updateMessages(cid, [response.message]); - - persistenceClient.disconnect(); - - flutterLocalNotificationsPlugin.show( - 1, - 'New message from ${response.message.user.name} in ${response.channel.name}', - response.message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'new_message', - 'New message notifications channel', - )), - ); - } -} - -FirebaseMessaging.onBackgroundMessage(onBackgroundMessage); -``` - diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/customize_message_actions.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/customize_message_actions.mdx deleted file mode 100644 index 564463c0b7..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/customize_message_actions.mdx +++ /dev/null @@ -1,81 +0,0 @@ ---- -id: customize_message_actions -title: Customize Message Actions ---- - -Customizing Message Actions - -### Introduction - -Message actions pop up in message overlay, when you long-press a message. - -![](../assets/message_actions.jpg) - -We have provided granular control over these actions. - -By default we render the following message actions: - -* edit message - -* delete message - -* reply - -* thread reply - -* copy message - -* flag message - -* pin message - -:::note -Edit and delete message are only available on messages sent by the user. -Additionally, pinning a message requires you to add the roles which are allowed to pin messages. -::: - -### Partially remove some message actions - -For example, if you only want to keep `"copy message"` and `"delete message"`, -here is how to do it using the `messageBuilder` with our `MessageWidget`. - -```dart -MessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - showFlagButton: false, - showEditMessage: false, - showCopyMessage: true, - showDeleteMessage: details.isMyMessage, - showReplyMessage: false, - showThreadReplyMessage: false, - ); - }, -) -``` - -### Add a new custom message action - -The SDK also allows you to add new actions into the dialog. - -For example, let's suppose you want to introduce a new message action - "Demo Action": - -We use the `customActions` parameter of the `MessageWidget` to add extra actions. - -```dart -MessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - customActions: [ - MessageAction( - leading: Icon(Icons.add), - title: Text('Demo Action'), - onTap: (message) { - /// Complete action here - }, - ), - ], - ); - }, -) -``` diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/customize_message_widget.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/customize_message_widget.mdx deleted file mode 100644 index 6949cdeb7c..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/customize_message_widget.mdx +++ /dev/null @@ -1,181 +0,0 @@ ---- -id: customize_message_widget -title: Customizing The MessageWidget ---- - -Customizing Text Messages - -### Introduction - -Every application provides a unique look and feel to their own messaging interface including and not -limited to fonts, colors, and shapes. - -This guide details how to customize the `MessageWidget` in the Stream Chat Flutter UI SDK. - -### Building Custom Messages - -This guide goes into detail about the ability to customize the `MessageWidget`. However, if you want -to customize the default `MessageWidget` in the `MessageListView` provided, you can use the `.copyWith()` method -provided inside the `messageBuilder` parameter of the `MessageListView` like this: - -```dart -MessageListView( - messageBuilder: (context, details, messageList, defaultImpl) { - // Your implementation of the message here - // E.g: return Text(details.message.text ?? ''); - }, -), -``` - -### Theming - -You can customize the `MessageWidget` using the `StreamChatTheme` class, so that you can change the -message theme at the top instead of creating your own `MessageWidget` at the lower implementation level. - -There are several things you can change in the theme including text styles and colors of various elements. - -You can also set a different theme for the user's own messages and messages received by them. - -:::note -Theming allows you to change minor factors like style while using the widget directly allows you much -more customization such as replacing a certain widget with another. Some things can only be customized -through the widget and not the theme. -::: - -Here is an example: - -```dart -StreamChatThemeData( - - /// Sets theme for user's messages - ownMessageTheme: MessageThemeData( - messageBackgroundColor: colorTheme.textHighEmphasis, - ), - - /// Sets theme for received messages - otherMessageTheme: MessageThemeData( - avatarTheme: AvatarThemeData( - borderRadius: BorderRadius.circular(8), - ), - ), - -) -``` - -![](../assets/message_theming.png) - -#### Change message text style - -The `MessageWidget` has multiple `Text` widgets that you can manipulate the styles of. The three main -are the actual message text, user name, message links, and the message timestamp. - -```dart -MessageThemeData( - messageTextStyle: TextStyle(...), - createdAtStyle: TextStyle(...), - messageAuthorStyle: TextStyle(...), - messageLinksStyle: TextStyle(...), -) -``` - -![](../assets/message_styles.png) - -#### Change avatar theme - -You can change the attributes of the avatar (if displayed) using the `avatarTheme` property. - -```dart -MessageThemeData( - avatarTheme: AvatarThemeData( - borderRadius: BorderRadius.circular(8), - ), -) -``` - -![](../assets/message_rounded_avatar.png) - -#### Changing Reaction theme - -You also customize the reactions attached to every message using the theme. - -```dart -MessageThemeData( - reactionsBackgroundColor: Colors.red, - reactionsBorderColor: Colors.redAccent, - reactionsMaskColor: Colors.pink, -), -``` - -![](../assets/message_reaction_theming.png) - -### Changing Message Actions - -When a message is long pressed, the `MessageActionsModal` is shown. - -The `MessageWidget` allows showing or hiding some options if you so choose. - -```dart -MessageWidget( - ... - showUsername = true, - showTimestamp = true, - showReactions = true, - showDeleteMessage = true, - showEditMessage = true, - showReplyMessage = true, - showThreadReplyMessage = true, - showResendMessage = true, - showCopyMessage = true, - showFlagButton = true, - showPinButton = true, - showPinHighlight = true, -), -``` - -![](../assets/message_widget_actions.png) - -### Building attachments - -The `customAttachmentBuilder` property allows you to build any kind of attachment (inbuilt or custom) -in your own way. While a separate guide is written for this, it is included here because of relevance. - -```dart -MessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - customAttachmentBuilders: { - 'location': (context, message, attachments) { - final attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'], - attachments[0].extraData['longitude'], - ), - ); - - return wrapAttachmentWidget(context, attachmentWidget, null, true, BorderRadius.circular(8.0)); - } - }, - ); - }, -), -``` - -### Widget Builders - -Some parameters allow you to construct your own widget in place of some elements in the `MessageWidget`. - -These are: -* `userAvatarBuilder` : Allows user to substitute their own widget in place of the user avatar. -* `editMessageInputBuilder` : Allows user to substitute their own widget in place of the input in edit mode. -* `textBuilder` : Allows user to substitute their own widget in place of the text. -* `bottomRowBuilder` : Allows user to substitute their own widget in the bottom of the message when not deleted. -* `deletedBottomRowBuilder` : Allows user to substitute their own widget in the bottom of the message when deleted. - -```dart -MessageWidget( - ... - textBuilder: (context, message) { - // Add your own text implementation here. - }, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/customize_text_messages.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/customize_text_messages.mdx deleted file mode 100644 index 35414268d6..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/customize_text_messages.mdx +++ /dev/null @@ -1,157 +0,0 @@ ---- -id: customize_text_messages -title: Customize Text Messages ---- - -Customizing Text Messages - -### Introduction - -Every application provides a unique look and feel to their own messaging interface including and not -limited to fonts, colors, and shapes. - -This guide details how to customize message text in the `MessageListView` / `MessageWidget` in the -Stream Chat Flutter UI SDK. - -:::note -This guide is specifically for the `MessageListView` but if you intend to display a `MessageWidget` -separately, follow the same process without the `.copyWith` and use the default constructor instead. -::: - -### Basics of customizing a `MessageWidget` - -First, add a `MessageListView` in the appropriate place where you intend to display messages from a -channel. - -```dart -MessageListView( - ... -) -``` - -Now, we use the `messageBuilder` parameter to build a custom message. The builder function also provides -the default implementation of the `MessageWidget` so that we can change certain aspects of the widget -without redoing all of the default parameters. - -:::note -In earlier versions of the SDK, some `MessageWidget` parameters were exposed directly through the `MessageListView`, -however, this quickly becomes hard to maintain as more parameters and customizations are added to the -`MessageWidget`. Newer version utilise a cleaner interface to change the parameters by supplying a -default message implementation as aforementioned. -::: - -```dart -MessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget; - }, -) -``` - -We use `.copyWith()` to customize the widget: - -```dart -MessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - ... - ); - }, -) -``` - -### Customizing text - -If you intend to simply change the theme for the text, you need not recreate the whole widget. The -`MessageWidget` has a `messageTheme` parameter that allows you to pass the theme for most aspects -of the message. - -```dart -MessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - messageTheme: MessageTheme( - ... - messageText: TextStyle(), - ), - ); - }, -) -``` - -If you want to replace the entire text widget in the `MessageWidget`, you can use the `textBuilder` -parameter which provides a builder for creating a widget to substitute the default text.parameter - -```dart -MessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - textBuilder: (context, message) { - return Text(message.text); - }, - ); - }, -) -``` - -### Adding Hashtags - -To add elements like hashtags, we can override the `textBuilder` in the MessageWidget: - -```dart -MessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - textBuilder: (context, message) { - final text = _replaceHashtags(message.text).replaceAll('\n', '\\\n'); - final messageTheme = StreamChatTheme.of(context).ownMessageTheme; - - return MarkdownBody( - data: text, - onTapLink: ( - String link, - String href, - String title, - ) { - // Do something with tapped hashtag - }, - styleSheet: MarkdownStyleSheet.fromTheme( - Theme.of(context).copyWith( - textTheme: Theme.of(context).textTheme.apply( - bodyColor: messageTheme.messageText.color, - decoration: messageTheme.messageText.decoration, - decorationColor: messageTheme.messageText.decorationColor, - decorationStyle: messageTheme.messageText.decorationStyle, - fontFamily: messageTheme.messageText.fontFamily, - ), - ), - ).copyWith( - a: messageTheme.messageLinks, - p: messageTheme.messageText, - ), - ); - }, - ); - }, -) - -String _replaceHashtags(String text) { - RegExp exp = new RegExp(r"\B#\w\w+"); - exp.allMatches(text).forEach((match){ - text = text.replaceAll( - '${match.group(0)}', '[${match.group(0)}](${match.group(0).replaceAll(' ', '')})'); - }); - return text; -} -``` - -We can replace the hashtags using RegEx and add links for the MarkdownBody which is done here in the -`_replaceHashtags()` function. -Inside the textBuilder, we use the `flutter_markdown` package to build our hashtags as links. - -![](../assets/hashtag_example.jpg) diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/end_to_end_chat_encryption.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/end_to_end_chat_encryption.mdx deleted file mode 100644 index 79ab543fc5..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/end_to_end_chat_encryption.mdx +++ /dev/null @@ -1,257 +0,0 @@ ---- -id: end_to_end_chat_encryption -title: End To End Chat Encryption ---- - -## Introduction - -When you communicate over a chat application with another person or group, -you may exchange sensitive information, like personally identifiable information, financial details, or passwords. -A chat application should use end-to-end encryption to ensure that users' data stays secure. - -:::note -Before you start, keep in mind that this guide is a basic example intended for educational purposes only. -If you want to implement end-to-end encryption in your production app, please consult a security professional first. -There’s a lot more to consider from a security perspective that isn’t covered here. -::: - -## What is End-to-End Encryption? - -End-to-end encryption (E2EE) is the process of securing a message from third parties so that only the sender and receiver can access the message. -E2EE provides security by storing the message in an encrypted form on the application's server or database. - -You can only access the message by decrypting and signing it using a known public key (distributed freely) -and a corresponding private key (only known by the owner). - -Each user in the application has their own public-private key pair. -Public keys are distributed publicly and encrypt the sender’s messages. -The receiver can only decrypt the sender’s message with the matching private key. - -Check out the diagram below for an example: - -![](../assets/end_to_end_encryption.png) - -## Setup - -### Dependencies - -Add the [`webcrypto`](https://pub.dev/packages/webcrypto) package in your `pubspec.yaml` file. - -```yaml -dependencies: - webcrypto: ^0.5.2 # latest version -``` - -### Generate Key Pair - -Write a function that generates a key pair using the **ECDH** algorithm and the **P-256** elliptic curve (**P-256** is well-supported and -offers the right balance of security and performance). - -The pair will consist of two keys: -- **PublicKey**: The key that is linked to a user to encrypt messages. -- **PrivateKey**: The key that is stored locally to decrypt messages. - -```dart -Future generateKeys() async { - final keyPair = await EcdhPrivateKey.generateKey(EllipticCurve.p256); - final publicKeyJwk = await keyPair.publicKey.exportJsonWebKey(); - final privateKeyJwk = await keyPair.privateKey.exportJsonWebKey(); - - return JsonWebKeyPair( - privateKey: json.encode(privateKeyJwk), - publicKey: json.encode(publicKeyJwk), - ); -} - -// Model class for storing keys -class JsonWebKeyPair { - const JsonWebKeyPair({ - required this.privateKey, - required this.publicKey, - }); - - final String privateKey; - final String publicKey; -} -``` - -### Generate a Cryptographic Key - -Next, create a symmetric **Cryptographic Key** using the keys generated in the previous step. -You will use those keys to encrypt and decrypt messages. - -```dart -// SendersJwk -> sender.privateKey -// ReceiverJwk -> receiver.publicKey -Future> deriveKey(String senderJwk, String receiverJwk) async { - // Sender's key - final senderPrivateKey = json.decode(senderJwk); - final senderEcdhKey = await EcdhPrivateKey.importJsonWebKey( - senderPrivateKey, - EllipticCurve.p256, - ); - - // Receiver's key - final receiverPublicKey = json.decode(receiverJwk); - final receiverEcdhKey = await EcdhPublicKey.importJsonWebKey( - receiverPublicKey, - EllipticCurve.p256, - ); - - // Generating CryptoKey - final derivedBits = await senderEcdhKey.deriveBits(256, receiverEcdhKey); - return derivedBits; -} -``` - -### Encrypting Messages - -Once you have generated the **Cryptographic Key**, you're ready to encrypt the message. -You can use the **AES-GCM** algorithm for its known security and performance balance and good browser availability. - -```dart -// The "iv" stands for initialization vector (IV). To ensure the encryption’s strength, -// each encryption process must use a random and distinct IV. -// It’s included in the message so that the decryption procedure can use it. -final Uint8List iv = Uint8List.fromList('Initialization Vector'.codeUnits); -``` - -```dart -Future encryptMessage(String message, List deriveKey) async { - // Importing cryptoKey - final aesGcmSecretKey = await AesGcmSecretKey.importRawKey(deriveKey); - - // Converting message into bytes - final messageBytes = Uint8List.fromList(message.codeUnits); - - // Encrypting the message - final encryptedMessageBytes = - await aesGcmSecretKey.encryptBytes(messageBytes, iv); - - // Converting encrypted message into String - final encryptedMessage = String.fromCharCodes(encryptedMessageBytes); - return encryptedMessage; -} -``` - -### Decrypting Messages - -Decrypting a message is the opposite of encrypting one. -To decrypt a message to a human-readable format, use the code snippet below: - -```dart -Future decryptMessage(String encryptedMessage, List deriveKey) async { - // Importing cryptoKey - final aesGcmSecretKey = await AesGcmSecretKey.importRawKey(deriveKey); - - // Converting message into bytes - final messageBytes = Uint8List.fromList(encryptedMessage.codeUnits); - - // Decrypting the message - final decryptedMessageBytes = - await aesGcmSecretKey.decryptBytes(messageBytes, iv); - - // Converting decrypted message into String - final decryptedMessage = String.fromCharCodes(decryptedMessageBytes); - return decryptedMessage; -} -``` - -## Implement as a Stream Chat Feature - -Now that your setup is complete you can use it to implement end-to-end encryption in your app. - -### Store User's Public Key - -The first thing you need to do is store the generated `publicKey` as an `extraData` property, in order -for other users to encrypt messages. - -```dart -// Generating keyPair using the function defined in above steps -final keyPair = generateKeys(); -``` - -```dart -await client.connectUser( - User( - id: 'cool-shadow-7', - name: 'Cool Shadow', - image: 'https://getstream.io/cool-shadow', - - // set publicKey as a extraData property - extraData: { 'publicKey': keyPair.publicKey }, - ), - client.devToken('cool-shadow-7').rawValue, -); -``` - -### Sending Encrypted Messages - -Now you will use the `encryptMessage()` function created in the previous steps to encrypt the message. - -To do that, you need to make some minor changes to the **MessageInput** widget. - -```dart -final receiverJwk = receiver.extraData['publicKey']; - -// Generating derivedKey using user's privateKey and receiver's publicKey -final derivedKey = await deriveKey(keyPair.privateKey, receiverJwk); -``` - -```dart -MessageInput( - - ... - - preMessageSending: (message) async { - // Encrypting the message text using derivedKey - final encryptedMessage = await encryptMessage(message.text, derivedKey); - - // Creating a new message with the encrypted message text - final newMessage = message.copyWith(text: encryptedMessage); - - return newMessage; - }, -), -``` - -`preMessageSending` is a parameter that allows your app to process the message before it goes to Stream’s server. -Here, you have used it to encrypt the message before sending it to Stream’s backend. - -### Showing Decrypted Messages - -Now, it’s time to decrypt the message and present it in a human-readable format to the receiver. - -You can customize the **MessageListView** widget to have a custom `messagebuilder`, that can decrypt the message. - -```dart -MessageListView( - ... - messageBuilder: (context, messageDetails, currentMessages, defaultWidget) { - // Retrieving the message from details - final message = messageDetails.message; - - // Decrypting the message text using the derivedKey - final decryptedMessageFuture = decryptMessage(message.text, derivedKey); - return FutureBuilder( - future: decryptedMessageFuture, - builder: (context, snapshot) { - if (snapshot.hasError) return Text('Error: ${snapshot.error}'); - if (!snapshot.hasData) return Container(); - - // Updating the original message with the decrypted text - final decryptedMessage = message.copyWith(text: snapshot.data); - - // Returning defaultWidget with updated message - return defaultWidget.copyWith( - message: decryptedMessage, - ); - }, - ); - }, -), -``` - -That's it. That's all you need to implement E2EE in a Stream powered chat app. - -For more details, check out our [end-to-end encrypted chat article](https://getstream.io/blog/end-to-end-encrypted-chat-in-flutter/#whats-end-to-end-encryption). diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/migration_guide_2_0.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/migration_guide_2_0.mdx deleted file mode 100644 index 9873778429..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/migration_guide_2_0.mdx +++ /dev/null @@ -1,297 +0,0 @@ ---- -id: mig_guide_2_0 -title: Migrating to 2.0 (Null-safety) ---- - -A Migration Guide For Switching To v2.0 Of The Flutter SDK - -### Overview - -v2.0 of the Stream Chat Flutter SDK brings along several changes - primarily making the SDK null-safe. -Null safety allows your apps to run faster, with fewer errors, and with less code. - -Check [this link](https://flutter.dev/docs/null-safety) for more about Null Safety in Flutter. - -This guide is intended to enumerate and better explain the changes in the SDK. - -The changes will be listed by package and a concise changelog will follow with more info. - -### Changelog of `stream_chat_flutter` - -#### 🛑️ Breaking Changes from 1.5.4 - -* Migrate this package to null safety - -* Renamed `ChannelImage` to `ChannelAvatar` - -* Updated `StreamChatThemeData.reactionIcons` to accept custom builder - -* Renamed `ColorTheme` properties to reflect the purpose of the colors - - * `ColorTheme.black` -> `ColorTheme.textHighEmphasis` - * `ColorTheme.grey` -> `ColorTheme.textLowEmphasis` - * `ColorTheme.greyGainsboro` -> `ColorTheme.disabled` - * `ColorTheme.greyWhisper` -> `ColorTheme.borders` - * `ColorTheme.whiteSmoke` -> `ColorTheme.inputBg` - * `ColorTheme.whiteSnow` -> `ColorTheme.appBg` - * `ColorTheme.white` -> `ColorTheme.barsBg` - * `ColorTheme.blueAlice` -> `ColorTheme.linkBg` - * `ColorTheme.accentBlue` -> `ColorTheme.accentPrimary` - * `ColorTheme.accentRed` -> `ColorTheme.accentError` - * `ColorTheme.accentGreen` -> `ColorTheme.accentInfo` - -* `ChannelListCore` options property is removed in favor of individual properties - - * `options.state` -> `bool state` - * `options.watch` -> `bool watch` - * `options.presence` -> `bool presence` - -* `UserListView` options property is removed in favor of individual properties - - * `options.presence` -> `bool presence` - -* Renamed `ImageHeader` to `GalleryHeader` - -* Renamed `ImageFooter` to `GalleryFooter` - -* `MessageBuilder` and `ParentMessageBuilder` signature is now - -```dart -typedef MessageBuilder = Widget Function( - BuildContext, - MessageDetails, - List, - MessageWidget defaultMessageWidget, - ); -``` - -The last parameter is the default `MessageWidget` -You can call `.copyWith` to customize just a subset of properties - -#### ✅ Added - -Added video compress options (frame and quality) to MessageInput -`TypingIndicator` now has a property called `parentId` to show typing indicator specific to threads -#493: add support for `MessageListView` header/footer -`MessageWidget` accepts a `userAvatarBuilder` -Added `pinMessage` UI support -Added `MessageListView.threadSeparatorBuilder` property -Added `MessageInput.onError` property to allow error handling -Added `GalleryHeader`/`GalleryFooter` theme classes - -#### 🐞 Fixed - -#483: Keyboard covers input text box when editing message -`Modals` are shown using the nearest `Navigator` to make using the SDK easier in a nested navigator use case -#484: messages don't update without a reload -`MessageListView` not rendering if the user is not a member of the channel -Fix `MessageInput` overflow when there are no actions -Minor fixes and improvements - -### Migrating to 2.0 for `stream_chat_flutter` - -:::note -If you are migrating your full Flutter project to null-safety, first make sure you follow the -instructions from the [official Null Safety migration guide](https://dart.dev/null-safety/migration-guide). -::: - -To migrate to v2.0 for `stream_chat_flutter`, first change the version of the package to the latest -null-safe version. - -```yaml -dependencies: - stream_chat_flutter: ^2.0.0 -``` - -Upon doing this, all breaking changes from the package will take immediate effect. Here are steps to -remedy the issues: - -1) Replace the offending class names with the revised class names - - * `ChannelImage` -> `ChannelAvatar` - * `ImageHeader` -> `GalleryHeader` - * `ImageFooter` -> `GalleryFooter` - -2) The new version comes with revised color names since the previous names do not suit light/dark mode -nomenclature. Make sure any old colors used from theme are changed over to the new theme color names: - - * `ColorTheme.black` -> `ColorTheme.textHighEmphasis` - * `ColorTheme.grey` -> `ColorTheme.textLowEmphasis` - * `ColorTheme.greyGainsboro` -> `ColorTheme.disabled` - * `ColorTheme.greyWhisper` -> `ColorTheme.borders` - * `ColorTheme.whiteSmoke` -> `ColorTheme.inputBg` - * `ColorTheme.whiteSnow` -> `ColorTheme.appBg` - * `ColorTheme.white` -> `ColorTheme.barsBg` - * `ColorTheme.blueAlice` -> `ColorTheme.linkBg` - * `ColorTheme.accentBlue` -> `ColorTheme.accentPrimary` - * `ColorTheme.accentRed` -> `ColorTheme.accentError` - * `ColorTheme.accentGreen` -> `ColorTheme.accentInfo` - -3) We decided to make messages easier to customize and now supply the default implementation of the -messages in the builder - so you can now customize a single parameter without having to redo the -entire implementation. Please reform your builders to take into account the new format: - -``` -typedef MessageBuilder = Widget Function( - BuildContext, - MessageDetails, - List, - MessageWidget defaultMessageWidget, - ); -``` - -To tweak any of the default properties individually, you can use `defaultMessageWidget.copyWith()`. - -### Changelog of `stream_chat_flutter_core` - -#### 🛑️ Breaking Changes from 1.5.3 - -* Migrate this package to null safety -* `channelsBloc.queryChannels()`, `ChannelListCore` options param/property is removed in favor of individual params/properties - * `options.state` -> `bool state` - * `options.watch` -> `bool watch` - * `options.presence` -> `bool presence` -* `usersBloc.queryUsers()`, `UserListCore` options param/property is removed in favor of individual params/properties - * `options.presence` -> `bool presence` - -#### ✅ Added - -* Monitor connection using `connectivity_plus` package - -#### 🐞 Fixed - -* Minor fixes -* Performance improvements - -### Migrating to 2.0 for `stream_chat_flutter_core` - -:::note -If you are migrating your full Flutter project to null-safety, first make sure you follow the -instructions from the [official Null Safety migration guide](https://dart.dev/null-safety/migration-guide). -::: - -To migrate to v2.0 for `stream_chat_flutter_core`, first change the version of the package to the latest -null-safe version. - -```yaml -dependencies: - stream_chat_flutter_core: ^2.0.0 -``` - -Upon doing this, all breaking changes from the package will take immediate effect. Here are steps to -remedy the issue: - -:::note -The major changes in `stream_chat_flutter_core` consist of changing over from a map full of options -to a more type safe and sound approach by changing over to explicit parameters. -::: - -1) Change over Core widget implementations by using the explicit parameters instead of the options map. -Use these explicit parameters in the widget constructor instead of the option keys: - - * `options.state` -> `bool state` - * `options.watch` -> `bool watch` - * `options.presence` -> `bool presence` - -2) Change over query calls in the BLoCs in the same way (change from options map to explicit parameters -in the constructor) - -### Changelog of `stream_chat` - -#### 🛑️ Breaking Changes from 1.5.3 - -* Migrate this package to null safety -* `ConnectUserWithProvider` now requires `tokenProvider` as a required parameter. (Removed from the constructor) -* `client.disconnect()` is now divided into two different functions - * `client.closeConnection()` -> for closing user web socket connection. - * `client.disconnectUser()` -> for disconnecting user and resetting client state. -* `client.devToken()` now returns a Token model instead of String. -* `ApiError` is removed in favor of `StreamChatError` - * `StreamChatError` -> parent type for all the stream errors. - * `StreamWebSocketError` -> for user web socket related errors. - * `StreamChatNetworkError` -> for network related errors. -* `client.queryChannels()`, `channel.query()` options parameter is removed in favor of individual parameters - * `option.state` -> `bool state` - * `option.watch` -> `bool watch` - * `option.presence` -> `bool presence` -* `client.queryUsers()` options parameter is removed in favor of individual parameters - * `option.presence` -> `bool presence` -* Added typed filters - -#### 🐞 Fixed - -* #369: Client does not return without internet connection -* Several minor fixes -* Performance improvements - -#### ✅ Added - -* New Location `enum` is introduced for easily changing the client location/baseUrl. -* New `client.openConnection()` and `client.closeConnection()` is introduced to connect/disconnect user WS connection. -* New `client.partialUpdateMessage` and `channel.partialUpdateMessage` methods -* `connectWebSocket` parameter in connect user calls to use the client in "connection-less" mode. - -#### 🔄 Changed - -* `baseURL` is now deprecated in favor of using Location to change data location. - -### Migrating to 2.0 for `stream_chat` - -If you are migrating your full Flutter project to null-safety, first make sure you follow the -instructions from the [official Null Safety migration guide](https://dart.dev/null-safety/migration-guide). -::: - -To migrate to v2.0 for `stream_chat`, first change the version of the package to the latest -null-safe version. - -```yaml -dependencies: - stream_chat: ^2.0.0 -``` - -Upon doing this, all breaking changes from the package will take immediate effect. Here are steps to -remedy the issues: - -1) Change over the constructor of `connectUserWithProvider()` to the new format which has `tokenProvider` as a required parameter. - -2) We added more nuance to `disconnectUser()` by adding two new methods - one to close the connection -and the other to disconnect the user. This allows more fine-grained control of disconnection. - - * `client.closeConnection()` -> for closing user web socket connection. - * `client.disconnectUser()` -> for disconnecting user and resetting client state. - -3) We refactored how we handle errors - new error types are now introduced that replace ApiError. - - * `StreamChatError` -> parent type for all the stream errors. - * `StreamWebSocketError` -> for user web socket related errors. - * `StreamChatNetworkError` -> for network related errors. - -4) We changed over from a map full of options to a more type-safe and sound approach by changing over to explicit parameters. - -Use these explicit parameters in the query parameters instead of the option keys: - -* `client.queryChannels()`, `channel.query()` options parameter is removed in favor of individual parameters - * `option.state` -> `bool state` - * `option.watch` -> `bool watch` - * `option.presence` -> `bool presence` -* `client.queryUsers()` options parameter is removed in favor of individual parameters - * `option.presence` -> `bool presence` - -5) We added type-safe filters to make filtering in the app easier. Change over the filters to the -new implementation. - -As an example, in the old app this filter: - -```dart - filter: { - 'members': { - '\$in': [StreamChat.of(context).user.id], - } - }, -``` - -Would turn into: - -```dart - filter: Filter.in_('members', [StreamChat.of(context).user.id]) -``` diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/understanding_filters.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/understanding_filters.mdx deleted file mode 100644 index c61d7b4fbd..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/understanding_filters.mdx +++ /dev/null @@ -1,193 +0,0 @@ ---- -id: understanding_filters -title: Understanding Filters ---- - -Understanding Filters - -### Introduction - -Filters are used to get a specific subset of objects (channels, users, messages, members, etc) which -fit the conditions specified. Earlier versions of the SDK contained String-based filters which are now replaced by type-safe -filters. This guide aims to explain the different types of filters and how to use them. - -### Types Of Filters - -#### Filter.equal - -The 'equal' filter gets the objects where the given key has the specified value. - -```dart -Filter.equal('type', 'messaging'), -``` - -#### Filter.notEqual - -The `notEqual` filter gets the objects where the given key does not have the specified value. - -```dart -Filter.notEqual('type', 'messaging'), -``` - -#### Filter.greater - -The 'greater' filter gets the objects where the given key has a higher value than the specified value. - -```dart -Filter.greater('count', 5), -``` - -#### Filter.greaterOrEqual - -The 'greaterOrEqual' filter gets the objects where the given key has an equal or higher value than the specified value. - -```dart -Filter.greaterOrEqual('count', 5), -``` - -#### Filter.less - -The 'less' filter gets the objects where the given key has a lesser value than the specified value. - -```dart -Filter.less('count', 5), -``` - -#### Filter.lessOrEqual - -The 'lessOrEqual' filter gets the objects where the given key has a lesser or equal value than the specified value. - -```dart -Filter.lessOrEqual('count', 5), -``` - -#### Filter.in_ - -The ``in_` filter allows getting objects where the key matches any in a specified array. - -```dart -Filter.in_('members', [user.id]) -``` - -:::note -Since `in` is a keyword in Dart, the filter has an underscore added. This does not apply to the `notIn` -keyword. -::: - -#### Filter.notIn - -The `notIn` filter allows getting objects where the key matches none in a specified array. - -```dart -Filter.notIn('members', [user.id]) -``` - -#### Filter.query - -The 'query' filter matches values by performing text search with the specified value. - -```dart -Filter.query('name', 'demo') -``` - -#### Filter.autoComplete - -The 'autoComplete' filter matches values with the specified prefix. - -```dart -Filter.autoComplete('name', 'demo') -``` - -#### Filter.exists - -The 'exists' filter matches values that exist, or don't exist, based on the specified boolean value. - -```dart -Filter.exists('name') -``` - -#### Filter.notExists - -The `notExists` filter checks if the specified key doesn't exist. This is a simplified call to `Filter.exists` -with the value set to false. - -```dart -Filter.notExists('name') -``` - -#### Filter.contains - -The 'contains' filter matches any list that contains the specified value. - -```dart -Filter.contains('teams', 'red') -``` - -#### Filter.empty - -The 'empty' filter constructor returns an empty filter. It's the equivalent of an empty map `{}`; - -```dart -Filter.empty(); -``` - -#### Filter.raw - -The 'raw' filter constructor lets you specify a raw filter. We suggest using this only if you can't manage to build what you want using the other constructors. - -```dart -Filter.raw(value: { - 'members': [ - ..._selectedUsers.map((e) => e.id), - chatState.currentUser!.id, - ], - 'distinct': true, -}); -``` - -#### Filter.custom - -The 'custom' filter is used to create a custom filter in case it does not exists or it's not been added to the SDK yet. -Note that the filter must be supported by the Stream backend in order to work. - -```dart -Filter.custom( - operator: '\$max', - value: 10, -) -``` - -### Group Queries - -#### Filter.and - -The 'and' operator combines multiple queries. - -```dart -final filter = Filter.and([ - Filter.equal('type', 'messaging'), - Filter.in_('members', [user.id]) -]) -``` - -#### Filter.or - -Combines the provided filters and matches the values matched by at least one of the filters. - -```dart -final filter = Filter.or([ - Filter.in_('bannedUsers', [user.id]), - Filter.in_('shadowBannedUsers', [user.id]) -]) -``` - -#### Filter.nor - -Combines the provided filters and matches the values not matched by all the filters. - -```dart -final filter = Filter.nor([ - Filter.in_('bannedUsers', [user.id]), - Filter.in_('shadowBannedUsers', [user.id]) -]) -``` diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/user_token_generation_with_firebase_auth.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/user_token_generation_with_firebase_auth.mdx deleted file mode 100644 index 0012dbda05..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/guides/user_token_generation_with_firebase_auth.mdx +++ /dev/null @@ -1,447 +0,0 @@ ---- -id: token_generation_with_firebase -title: User Token Generation With Firebase Auth and Cloud Functions ---- - -Securely generate Stream Chat user tokens using Firebase Authentication and Cloud Functions. - -:::note -This guide assumes that you are familiar with Firebase Authentication and Cloud Functions for Flutter and using the Flutter Stream Chat SDK. -::: - -### Introduction - -In this guide, you'll explore how you can use Firebase Auth as an authentication provider and create Firebase Cloud functions to securely -generate Stream Chat user tokens. - -You will use Stream's [NodeJS client](https://getstream.io/chat/docs/node/?language=javascript) for Stream account creation and -token generation, and [Flutter Cloud Functions for Firebase](https://firebase.flutter.dev/docs/functions/overview) to invoke the cloud functions -from your Flutter app. - -Stream supports several different [backend clients](https://getstream.io/chat/sdk/#backend-clients) to integrate with your server. This guide only shows an easy way to integrate Stream Chat authentication using Firebase and Flutter. - -### Flutter Firebase - -See the [Flutter Firebase getting started](https://firebase.flutter.dev/docs/overview) docs for setup and installation instructions. - -You will also need to add the [Flutter Firebase Authentication](https://firebase.flutter.dev/docs/auth/overview), and [Flutter Firebase Cloud Functions](https://firebase.flutter.dev/docs/functions/overview) packages to your app. Depending on the platform that you target, there may be specific configurations that you need to do. - -#### Starting Code - -The following code shows a basic application with **FirebaseAuth** and **FirebaseFunctions**. - -You will extend this later to execute cloud functions. - -```dart -import 'package:cloud_functions/cloud_functions.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:flutter/material.dart'; -import 'dart:async'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - await Firebase.initializeApp(); - runApp(MyApp()); -} - -class MyApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - body: Auth(), - ), - ); - } -} - -class Auth extends StatefulWidget { - Auth({Key? key}) : super(key: key); - - @override - _AuthState createState() => _AuthState(); -} - -class _AuthState extends State { - late FirebaseAuth auth; - late FirebaseFunctions functions; - - @override - void initState() { - super.initState(); - auth = FirebaseAuth.instance; - functions = FirebaseFunctions.instance; - } - - final email = 'test@getstream.io'; - final password = 'password'; - - Future createAccount() async { - // Create Firebase account - await auth.createUserWithEmailAndPassword(email: email, password: password); - print('Firebase account created'); - } - - Future signIn() async { - // Sign in with Firebase - await auth.signInWithEmailAndPassword(email: email, password: password); - print('Firebase signed in'); - } - - Future signOut() async { - // Revoke Stream chat token. - final callable = functions.httpsCallable('revokeStreamUserToken'); - await callable(); - print('Stream user token revoked'); - } - - @override - Widget build(BuildContext context) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - AuthenticationState( - streamUser: auth.authStateChanges(), - ), - ElevatedButton( - onPressed: createAccount, - child: Text('Create account'), - ), - ElevatedButton( - onPressed: signIn, - child: Text('Sign in'), - ), - ElevatedButton( - onPressed: signOut, - child: Text('Sign out'), - ), - ], - ), - ); - } -} - -class AuthenticationState extends StatelessWidget { - const AuthenticationState({ - Key? key, - required this.streamUser, - }) : super(key: key); - - final Stream streamUser; - - @override - Widget build(BuildContext context) { - return StreamBuilder( - stream: streamUser, - builder: (context, snapshot) { - if (snapshot.hasData) { - return (snapshot.data != null) - ? Text('Authenticated') - : Text('Not Authenticated'); - } - return Text('Not Authenticated'); - }, - ); - } -} - -``` - -Running the above will give this: - -![](../assets/authentication_demo_app.jpg) - -The `Auth` widget handles all of the authentication logic. It initializes a `FirebaseAuth.instance` and uses that -in the `createAccount`, `signIn` and `signOut` methods. There is a button to invoke each of these methods. - -The `FirebaseFunctions.instance` will be used later in this guide. - -The `AuthenticationState` widget listens to `auth.authStateChanges()` to display a message -indicating if a user is authenticated. - -### Firebase Cloud Functions - -Firebase Cloud Functions allows you to extend Firebase with custom operations that an event can trigger: -- **Internal event**: For example, when creating a new Firebase account this is automatically triggered. -- **External event**: For example, directly calling a cloud function from your Flutter application. - -To set up your local environment to deploy cloud functions, please see the -[Cloud Functions getting started](https://firebase.flutter.dev/docs/overview) docs. - -After initializing your project with cloud functions, you should have a **functions** folder in your project, including a `package.json` file. - -There should be two dependencies already added, **firebase-admin** and **firebase-functions**. You will also need to add the **stream-chat** dependency. - -Navigate to the **functions** folder and run `npm install stream-chat --save-prod`. - -This will install the node module and add it as a dependency to `package.json`. - -Now open `index.js` and add the following (this is the complete example): - -```js -const StreamChat = require('stream-chat').StreamChat; -const functions = require("firebase-functions"); -const admin = require("firebase-admin"); - -admin.initializeApp(); - -const serverClient = StreamChat.getInstance(functions.config().stream.key, functions.config().stream.secret); - - -// When a user is deleted from Firebase their associated Stream account is also deleted. -exports.deleteStreamUser = functions.auth.user().onDelete((user, context) => { - return serverClient.deleteUser(user.uid); -}); - -// Create a Stream user and return auth token. -exports.createStreamUserAndGetToken = functions.https.onCall(async (data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - // Create user using the serverClient. - await serverClient.upsertUser({ - id: context.auth.uid, - name: context.auth.token.name, - email: context.auth.token.email, - image: context.auth.token.image, - }); - - /// Create and return user auth token. - return serverClient.createToken(context.auth.uid); - } catch (err) { - console.error(`Unable to create user with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not create Stream user"); - } - } -}); - -// Get Stream user token. -exports.getStreamUserToken = functions.https.onCall((data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - return serverClient.createToken(context.auth.uid); - } catch (err) { - console.error(`Unable to get user token with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not get Stream user"); - } - } -}); - -// Revoke the authenticated user's Stream chat token. -exports.revokeStreamUserToken = functions.https.onCall((data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - return serverClient.revokeUserToken(context.auth.uid); - } catch (err) { - console.error(`Unable to revoke user token with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not get Stream user"); - } - } -}); - -``` - -First, you import the necessary packages and call `admin.initializeApp();` to set up Firebase cloud functions. - -Next, you initialize the **StreamChat** server client by calling `StreamChat.getInstance`. This function requires your Stream app's -**token** and **secret**. You can get this from the Stream Dashboard for your app. - -Set these values as environment data on Firebase Functions. - -```bash - firebase functions:config:set stream.key="app-key" stream.secret="app-secret" -``` - -*Replace **app-key** and **app-secret** with the values for your Stream app.* - -This creates an object of **stream** with properties **key** and **secret**. To access this environment -data use `functions.config().stream.key` and `functions.config().stream.secret`. - -See the [Firebase environment configuration](https://firebase.google.com/docs/functions/config-env) -documentation for additional information. - -To deploy these functions to Firebase, run: - -```bash -firebase deploy --only functions -``` - -### Create a Stream User and Get the User's Token - -In the `createStreamUserAndGetToken` cloud function you create an `onCall` HTTPS handler, which exposes -a cloud function that can be invoked from your Flutter app. - -```js -// Create a Stream user and return auth token. -exports.createStreamUserAndGetToken = functions.https.onCall(async (data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - // Create user using the serverClient. - await serverClient.upsertUser({ - id: context.auth.uid, - name: context.auth.token.name, - email: context.auth.token.email, - image: context.auth.token.image, - }); - - /// Create and return user auth token. - return serverClient.createToken(context.auth.uid); - } catch (err) { - console.error(`Unable to create user with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not create Stream user"); - } - } -}); -``` - -This function first does a check to see that the client that calls it is authenticated, -by ensuring that `context.auth` is not null. If it is null, then it throws an `HttpsError` with a descriptive -message. This error can be caught in your Flutter application. - -If the caller is authenticated the function proceeds to use the `serverClient` to create a new Stream Chat -user by calling the `upsertUser` method and passing in some user data. It uses the authenticated caller's **`uid`** as an **id**. - -After the user is created it generates a token for that user. This token is then returned to the caller. - -To call this from Flutter, you will need to use the `cloud_functions` package. - -Update the **`createAccount`** method in your Flutter code to the following: - -```dart -Future createAccount() async { - // Create Firebase account - await auth.createUserWithEmailAndPassword(email: email, password: password); - print('Firebase account created'); - - // Create Stream user and get token - final callable = functions.httpsCallable('createStreamUserAndGetToken'); - final results = await callable(); - print('Stream account created, token: ${results.data}'); -} -``` - -Calling this method will do the following: -1. Create a new Firebase User and authenticate that user. -2. Call the `createStreamUserAndGetToken` cloud function and get the Stream user token for the authenticated user. - -As you can see, calling a cloud function is easy and will also send all the necessary user authentication information (such as the UID) -in the request. - -Once you have the Stream user token, you can authenticate your Stream Chat user as you normally would. - -Please see our [initialization documentation](https://getstream.io/chat/docs/flutter-dart/init_and_users/?language=dart) for more information. - -As you can see below, the User ID matches on both Firebase's and Stream's user database. - -##### Firebase Authentication Database - -![Firebase Auth Database with new user created](../assets/firebase_authentication_dashboard.jpg) - -##### Stream Chat User Database - -![Stream chat user database new account created](../assets/stream_chat_user_database.jpg) - - -### Get the Stream User Token - -The `getStreamUserToken` cloud function is very similar to the `createStreamUserAndGetToken` function. The only difference is -that it only creates a user token and does not create a new user account on Stream. - -Update the **`signIn`** method in your Flutter code to the following: - -```dart -Future signIn() async { - // Sign in with Firebase - await auth.signInWithEmailAndPassword(email: email, password: password); - print('Firebase signed in'); - - // Get Stream user token - final callable = functions.httpsCallable('getStreamUserToken'); - final results = await callable(); - print('Stream user token retrieved: ${results.data}'); -} -``` - -Calling this method will do the following: -1. Sign in using Firebase Auth. -2. Call the `getStreamUserToken` cloud function to get a Stream user token. - -:::note -The user needs to be authenticated to call this cloud function. Otherwise, the function will throw -the **failed-precondition** error that you specified. -::: - -### Revoke Stream User Token - -You may also want to revoke the Stream user token if you sign out from Firebase. - -Update the `signOut` method in your Flutter code to the following: - -```dart -Future signOut() async { - // Revoke Stream user token. - final callable = functions.httpsCallable('revokeStreamUserToken'); - await callable(); - print('Stream user token revoked'); - - // Sign out Firebase. - await auth.signOut(); - print('Firebase signed out'); -} -``` -:::note -Call the cloud function before signing out from Firebase. -::: - -### Delete Stream User - -When deleting a Firebase user account, it would make sense also to delete the -associated Stream user account. - -The cloud function looks like this: - -```js -// When a user is deleted from Firebase their associated Stream account is also deleted. -exports.deleteStreamUser = functions.auth.user().onDelete((user, context) => { - return serverClient.deleteUser(user.uid); -}); -``` - -In this function, you are listening to delete events on Firebase auth. When an account is deleted, this function will be triggered, and you can get the -user's **`uid`** and call the `deleteUser` method on the `serverClient`. - -This is not an external cloud function; it can only be triggered when an -account is deleted. - -### Conclusion - -In this guide, you have seen how to securely create Stream Chat tokens using -Firebase Authentication and Cloud Functions. - -The principles shown in this guide can be applied to your preferred authentication -provider and cloud architecture of choice. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/_category_.json b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/_category_.json deleted file mode 100644 index 242afb7be9..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Stream Chat Flutter", - "position": 3 -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/channel_header.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/channel_header.mdx deleted file mode 100644 index 182df6b32f..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/channel_header.mdx +++ /dev/null @@ -1,83 +0,0 @@ ---- -id: channel_header -title: ChannelHeader ---- - -A Widget To Display Common Channel Details - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/ChannelHeader-class.html) - -![](../assets/channel_header.png) - -### Background - -When a user opens a channel, it is helpful to provide context of which channel they are in. This may -be in the form of a channel name or the users in the channel. Along with that, there also needs to be -a way for the user to look at more details of the channel (media, pinned messages, actions, etc.) and -preferably also a way to navigate back to where they came from. - -To encapsulate all of this functionality into one widget, the Flutter SDK contains a `ChannelHeader` -widget which provides these out of the box. - -### Basic Example - -Let's just add a `ChannelHeader` to a page with a `MessageListView` and a `MessageInput` to display -and send messages. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: ChannelHeader(), - body: Column( - children: [ - Expanded( - child: MessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, - ), - ), - MessageInput(), - ], - ), - ); - } -} -``` - -### Customizing Parts Of The Header - -The header works like a `ListTile` widget. - -Use the `title`, `subtitle`, `leading`, or `actions` parameters to substitute the widgets for your own. - -```dart -//... -ChannelHeader( - title: Text('My Custom Name'), -), -``` - -![](../assets/channel_header_custom_title.png) - -### Showing Connection State - -The `ChannelHeader` can also display connection state below the tile which shows the user if they -are connected or offline, etc. on connection events. - -To enable this, use the `showConnectionStateTile` property. - -```dart -//... -ChannelHeader( - showConnectionStateTile: true, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/channel_list_header.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/channel_list_header.mdx deleted file mode 100644 index d07a5cdc04..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/channel_list_header.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -id: channel_list_header -title: ChannelListHeader ---- - -A Header Widget For A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/ChannelListHeader-class.html) - -![](../assets/channel_list_header.png) - -### Background - -A common pattern for most messaging apps is to show a list of Channels (chats) on the first screen -and navigate to an individual one on being clicked. On this first page where the list of channels are -displayed, it is usual to have functionality such as adding a new chat, display the user logged in, etc. - -To encapsulate all of this functionality into one widget, the Flutter SDK contains a `ChannelListHeader` -widget which provides these out of the box. - -### Basic Example - -This is a basic example of a page which has a `ChannelListView` and a `ChannelListHeader` to recreate a -common Channels Page. - -```dart -class DemoPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: ChannelListHeader(), - body: ChannelsBloc( - child: ChannelListView( - filter: Filter.in_('members', [StreamChat.of(context).user.id]), - sort: [SortOption('last_message_at')], - pagination: PaginationParams( - limit: 20, - ), - channelWidget: ChannelPage(), - ), - ), - ); - } -} -``` - -### Customizing Parts Of The Header - -The header works like a `ListTile` widget. - -Use the `titleBuilder`, `subtitle`, `leading`, or `actions` parameters to substitute the widgets for your own. - -```dart -//... -ChannelListHeader( - subtitle: Text('My Custom Subtitle'), -), -``` - -![](../assets/channel_list_header_custom_subtitle.png) - -The `titleBuilder` parameter helps you build different titles depending on the connection state: - -```dart -//... -ChannelListHeader( - titleBuilder: (context, status, client) { - switch(status) { - /// Return your title widget - } - }, -), -``` - -### Showing Connection State - -The `ChannelListHeader` can also display connection state below the tile which shows the user if they -are connected or offline, etc. on connection events. - -To enable this, use the `showConnectionStateTile` property. - -```dart -//... -ChannelListHeader( - showConnectionStateTile: true, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/channel_list_view.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/channel_list_view.mdx deleted file mode 100644 index aaf5d566a0..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/channel_list_view.mdx +++ /dev/null @@ -1,110 +0,0 @@ ---- -id: channel_list_view -title: ChannelListView ---- - -A Widget For Displaying A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/ChannelListView-class.html) - -![](../assets/channel_list_view.png) - -### Background - -Channels are fundamental elements of Stream Chat and constitute shared spaces which allow users to -message each other. - -1:1 conversations and groups are both examples of channels, albeit with some (distinct/non-distinct) -differences. Displaying the list of channels that a user is a part of is a pattern present in most messaging apps. - -The `ChannelListView` widget allows displaying a list of channels to a user. By default, this is NOT -ONLY the channels that the user is a part of. This section goes into setting up and using a `ChannelListView` -widget. - -### Basic Example - -Here is a basic example of the `ChannelListView` widget. It consists of the main widget itself, a `Filter` -to filter only the channels that the user is a part of, sorting by last message time, pagination parameters, -and the widget to use when a particular channel is clicked. - -```dart -class ChannelListPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - body: ChannelsBloc( - child: ChannelListView( - filter: Filter.in_('members', [StreamChat.of(context).user.id]), - sort: [SortOption('last_message_at')], - pagination: PaginationParams( - limit: 20, - ), - channelWidget: ChannelPage(), - ), - ), - ); - } -} -``` - -This example by default displays the channels that a user is a part of. Now let's look at customizing -the widget. - -### Customizing the Channel Preview - -A common aspect of the widget needed to be tweaked according to each app is the Channel Preview (the -Channel tile in the list). To do this, we use the `channelPreviewBuilder` parameter like this: - -```dart -ChannelListView( - ... - channelPreviewBuilder: (context, channel) { - return ListTile( - tileColor: Colors.amberAccent, - title: Center( - child: ChannelName(), - ), - ); - }, -), -``` - -Which gives you a new Channel preview in the list: - -![](../assets/channel_preview.png) - -### Adding Swipe Actions - -To add actions (such as delete, more info, etc) when Channel preview is swiped left, set the `swipeToAction` -parameter to `true`. - -```dart -ChannelListView( - ... - swipeToAction: true, -), -``` - -This adds two basic actions - info and delete: - -![](../assets/swipe_channel.png) - -To add custom actions of your own, use the `swipeActions` parameter: - -```dart -ChannelListView( - ... - swipeToAction: true, - swipeActions: [ - SwipeAction( - color: Colors.blue, - iconWidget: Icon(Icons.add), - onTap: (channel) { - // Things to do on icon tap - }, - ), - // Other actions here - ] -), -``` - diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/introduction.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/introduction.mdx deleted file mode 100644 index 8be1ffabe0..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/introduction.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -id: introduction -title: Introduction ---- - -Understanding The UI Package Of The Flutter SDK - -### What function does `stream_chat_flutter` serve? - -The UI SDK (`stream_chat_flutter`) contains official Flutter components for Stream Chat, a service for building chat applications. - -While the Stream Chat service provides the backend for messaging and the LLC provides an easy way to -use it in your Flutter apps, we wanted to make sure that adding Chat functionality to your app was as quick as possible. - -The UI package is built on top of the low-level client and the core package and allows you to build a -full fledged app with either the inbuilt components, modify existing components, or easily add widgets -of your own to match your app's style better. diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/message_input.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/message_input.mdx deleted file mode 100644 index 1045af9b07..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/message_input.mdx +++ /dev/null @@ -1,169 +0,0 @@ ---- -id: message_input -title: MessageInput ---- - -A Widget Dealing With Everything Related To Sending A Message - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/MessageInput-class.html) - -![](../assets/message_input.png) - -### Background - -In Stream Chat, we can send messages in a channel. However, sending a message isn't as simple as adding -a `TextField` and logic for sending a message. It involves additional processes like addition of media, -quoting a message, adding a custom command like a GIF board, and much more. Moreover, most apps also -need to customize the input to match their theme, overall color and structure pattern, etc. - -To do this, we created a `MessageInput` widget which abstracts all expected functionality a modern input -needs - and allows you to use it out of the box. - -### Basic Example - -A `StreamChannel` is required above the widget tree in which the `MessageInput` is rendered since the channel is -where the messages sent actually go. Let's look at a common example of how we could use the `MessageInput`: - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: ChannelHeader(), - body: Column( - children: [ - Expanded( - child: MessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, - ), - ), - MessageInput(), - ], - ), - ); - } -} -``` - -It is common to put this widget in the same page of a `MessageListView` as the bottom widget. - -### Quoting A Message - -The quoting functionality allows us to 'reply' to a specific message without creating a thread out of it. -It adds the other message as context when sending a message and also displays it above the sent message. - -To quote a message, we provide a `quotedMessage` to the `MessageInput`. - -```dart -Message? message; - -// ... -MessageInput( - quotedMessage: message, -), -``` - -This will add the message given above the message about to be sent. - -While you can implement your own functionality to select which message to reply to, the `MessageListView` -widget helps in this case since it has an inbuilt `onMessageSwiped` callback which we can use. - -```dart - -class ChannelPage extends StatefulWidget { - @override - _ChannelPageState createState() => _ChannelPageState(); -} - -class _ChannelPageState extends State { - Message? quotedMessage; - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Column( - children: [ - Expanded( - child: MessageListView( - // ... - onMessageSwiped: (message) { - setState(() { - quotedMessage = message; - }); - }, - ), - ), - MessageInput( - quotedMessage: _quotedMessage, - onQuotedMessageCleared: () { - setState(() => _quotedMessage = null); - }, - ), - ], - ), - ); - } -} -``` - -![](../assets/message_input_quoted_message.png) - -### Adding Custom Actions - -By default, the `MessageInput` has two actions: one for attachments and one for commands like Giphy. -To add your own action, we use the `actions` parameter like this: - -```dart -MessageInput( - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20.0, - color: StreamChatTheme.of(context).colorTheme.grey, - ), - onTap: () { - // Do something here - }, - ), - ], -), -``` - -This will add on your action to the existing ones. - -### Disable Attachments - -To disable attachments being added to the message, set the `disableAttachments` parameter to true. - -```dart -MessageInput( - disableAttachments: true, -), -``` - -### Changing Position Of MessageInput Components - -You can also change the position of the TextField, actions and 'send' button relative to each other. - -To do this, use the `actionsLocation` or `sendButtonLocation` parameters which help you decide the location -of the buttons in the input. - -For example, if we want the actions on the right and the send button inside the TextField, we can do: - -```dart -MessageInput( - sendButtonLocation: SendButtonLocation.inside, - actionsLocation: ActionsLocation.right, -), -``` - -![](../assets/message_input_change_position.png) diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/message_list_view.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/message_list_view.mdx deleted file mode 100644 index 1f5dd3cbab..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/message_list_view.mdx +++ /dev/null @@ -1,114 +0,0 @@ ---- -id: message_list_view -title: MessageListView ---- - -A Widget For Displaying A List Of Messages - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/MessageListView-class.html) - -![](../assets/message_list_view.png) - -### Background - -Every channel can contain a list of messages sent by users inside it. The `MessageListView` widget -displays the list of messages inside a particular channel along with possible attachments and -other message attributes (if the message is pinned for example). This sets it apart from the `MessageSearchListView` -which may not contain messages only from a single channel and is used to search for messages across -many. - -### Basic Example - -The `MessageListView` shows the list of messages of the current channel. It has inbuilt support for -common messaging functionality: displaying and editing messages, adding / modifying reactions, support -for quoting messages, pinning messages, and more. - -An example of how you can use the MessageListView is: - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: ChannelHeader(), - body: Column( - children: [ - Expanded( - child: MessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, - ), - ), - MessageInput(), - ], - ), - ); - } -} -``` - -### Enable Threads - -Threads are made of a parent message and replies linked to it. To enable threading, the SDK requires you -to supply a `threadBuilder` which will supply the page when the thread is clicked. - -```dart -MessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, -), -``` - -![](../assets/message_list_view_threads.png) - -The `MessageListView` itself can render the thread by supplying the `parentMessage` parameter. - -```dart -MessageListView( - parentMessage: parent, -), -``` - -### Building Custom Messages - -You can also supply your own implementation for displaying messages using the `messageBuilder` parameter. - -:::note -To customize the existing implementation, look at the `MessageWidget` documentation instead. -::: - -```dart -MessageListView( - messageBuilder: (context, details, messageList, defaultImpl) { - // Your implementation of the message here - // E.g: return Text(details.message.text ?? ''); - }, -), -``` - -### Enabling Message Pinning - -Message pins save and highlight the message in the `MessageListView`. To enable users to pin the message, -make sure the pin permissions are granted for different types of users on the dashboard. After confirming -the appropriate users have permissions, add the user types in the `pinPermissions` parameter. - -```dart -MessageListView( - //... - pinPermissions: ['admin', 'userType1', 'userType2'], -), -``` - -This will allow these user types to pin messages through the message actions modal. - -![](../assets/message_list_view_pin.png) diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/message_search_list_view.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/message_search_list_view.mdx deleted file mode 100644 index c3d4a4537f..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/message_search_list_view.mdx +++ /dev/null @@ -1,61 +0,0 @@ ---- -id: message_search_list_view -title: MessageSearchListView ---- - -A Widget To Search For Messages Across Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/MessageSearchListView-class.html) - -![](../assets/message_search_list_view.png) - -### Background - -Users in Stream Chat can have several channels and it can get hard to remember which channel has the -message they are searching for. As such, there needs to be a way to search for a message across multiple -channels. This is where `MessageSearchListView` comes in. - -### Basic Example - -While the MessageListView is tied to a certain `StreamChannel`, a `MessageSearchListView` is not. - -```dart -class MessageSearchPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - body: MessageSearchBloc( - child: MessageSearchListView( - filters: Filter.in_('members', [StreamChat.of(context).user!.id],), - messageQuery: 'your query here', - limit: 20, - ), - ), - ); - } -} -``` - -### Customize The Result Tiles - -You can use your own widget for the result items using the `itemBuilder` parameter. - -```dart -MessageSearchListView( - // ... - itemBuilder: (context, response) { - return Text(response.message.text); - }, -), -``` - -### Show Result Count - -You show the number of results via the `showResultCount` parameter. - -```dart -MessageSearchListView( - // ... - showResultCount: true, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/message_widget.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/message_widget.mdx deleted file mode 100644 index 6c972175d4..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/message_widget.mdx +++ /dev/null @@ -1,97 +0,0 @@ ---- -id: message_widget -title: MessageWidget ---- - -A Widget For Displaying Messages And Attachments - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/MessageWidget-class.html) - -### Background - -There are several things that need to be displayed with text in a message in a modern messaging app: -attachments, highlights if the message is pinned, user avatars of the sender, etc. - -To encapsulate all of this functionality into one widget, the Flutter SDK contains a `MessageWidget` -widget which provides these out of the box. - -### Basic Example (Modifying `MessageWidget` in `MessageListView`) - -Primarily, the `MessageWidget` is used in the `MessageListView`. To customize only a few properties -of the `MessageWidget` without supplying all other properties, the `messageBuilder` builder supplies -a default implementation of the widget for us to modify. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: MessageListView( - messageBuilder: (context, details, messageList, defaultMessageWidget) { - return defaultMessageWidget.copyWith( - showThreadReplyIndicator: false, - ); - }, - ), - - ); - } -} -``` - -### Building A Custom Attachment - -When a custom attachment type (location, audio, etc.) is sent, the MessageWidget also needs to know -how to build it. For this purpose, we can use the `customAttachmentBuilders` parameter. - -As an example, if a message has a attachment type 'location', we do: - -```dart -MessageWidget( - //... - customAttachmentBuilders: { - 'location': (context, message, attachments) { - var attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'], - attachments[0].extraData['longitude'], - ), - ); - - return wrapAttachmentWidget(context, attachmentWidget, null, true, BorderRadius.circular(8.0)); - } - }, -) -``` - -You can also override the builder for existing attachment types like `image` and `video`. - -### Show User Avatar For Messages - -You can decide to show, hide, or remove user avatars of the sender of the message. To do this, set -the `showUserAvatar` property like this: - -```dart -MessageWidget( - //... - showUserAvatar = DisplayWidget.show, -) -``` - -### Reverse the message - -In most cases, `MessageWidget` needs to be a different orientation depending upon if the sender is the -user or someone else. - -For this, we use the `reverse` parameter to change the orientation of the message: - -```dart -MessageWidget( - //... - reverse = true, -) -``` diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/setup.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/setup.mdx deleted file mode 100644 index 9203e837bf..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/setup.mdx +++ /dev/null @@ -1,47 +0,0 @@ ---- -id: setup -title: Setup ---- - -Understanding Setup For `stream_chat_flutter` - -### Add pub.dev dependency - -First, you need to add the `stream_chat_flutter` dependency to your `pubspec.yaml`. - -You can either run this command: - -```shell -flutter pub add stream_chat_flutter -``` - -OR - -Add this line in the dependencies section of your pubspec.yaml after substituting latest version: - -```yaml -dependencies: - stream_chat_flutter: ^latest_version -``` - -You can find the package details on [pub.dev](https://pub.dev/packages/stream_chat_flutter). - -### Details On Platform Support - -`stream_chat_flutter` was originally created for Android and iOS mobile platforms. As Flutter matured, -support for additional platforms was added and the package now has experimental support for web and desktop as -[detailed here](https://getstream.io/blog/announcing-experimental-multi-platform-support-for-the-stream-flutter-sdk/). - -However, platforms other than mobile may have additional constraints due to not supporting all plugins, -which will be addressed by the respective plugin creators over time. - -### Setup: iOS - -The library uses [flutter file picker plugin](https://github.com/miguelpruivo/flutter_file_picker) to pick files from the os. -Follow [this wiki](https://github.com/miguelpruivo/flutter_file_picker/wiki/Setup#ios) to fulfill iOS requirements. - -We also use [`video_player`](https://pub.dev/packages/video_player) to reproduce videos. -Follow [this guide](https://pub.dev/packages/video_player#installation) to fulfill the requirements. - -To pick images from the camera, we use the [`image_picker`](https://pub.dev/packages/image_picker) plugin. -Follow [these instructions](https://pub.dev/packages/image_picker#ios) to check the requirements. diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/stream_chat_and_theming.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/stream_chat_and_theming.mdx deleted file mode 100644 index 422639cf2d..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/stream_chat_and_theming.mdx +++ /dev/null @@ -1,70 +0,0 @@ ---- -id: stream_chat_and_theming -title: StreamChat And Theming ---- - -Understanding How To Customize Widgets Using `StreamChatTheme` - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChatTheme-class.html) and [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChatThemeData-class.html) - -### Background - -Stream's UI SDK makes it easy for developers to add custom styles and attributes to our widgets. Like most Flutter frameworks, Stream exposes a dedicated widget for theming. - -Using `StreamChatTheme`, users can customize most aspects of our UI widgets by setting attributes using `StreamChatThemeData`. - -Similar to the `Theme` and `ThemeData` in Flutter, Stream Chat uses a top level [inherited widget](https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html) to provide theming information throughout your application. This can be optionally set at the top of your application tree or at a localized point in your widget sub-tree. - -If you'd like to customize the look and feel of Stream chat across your entire application, we recommend setting your theme at the top level. Conversely, users can customize specific screens or widgets by wrapping components in a `StreamChatTheme`. - -### A closer look at StreamChatThemeData - -Looking at the constructor for `StreamChatThemeData`, 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 `ChannelHeader`, `MessageInputs`, etc. have been broken up into smaller theme objects. - -```dart -factory StreamChatThemeData({ - Brightness? brightness, - TextTheme? textTheme, - ColorTheme? colorTheme, - ChannelListHeaderTheme? channelListHeaderTheme, - ChannelPreviewTheme? channelPreviewTheme, - ChannelTheme? channelTheme, - MessageTheme? otherMessageTheme, - MessageTheme? ownMessageTheme, - MessageInputTheme? messageInputTheme, - Widget Function(BuildContext, Channel)? defaultChannelImage, - Widget Function(BuildContext, User)? defaultUserImage, - IconThemeData? primaryIconTheme, - List? reactionIcons, - }); -``` - -### Stream Chat Theme in use - -Let's take a look at customizing widgets using `StreamChatTheme`. In the example below, we can change the default color theme to yellow and override the channel header's typography and colors. - -```dart -builder: (context, child) => StreamChat( - client: client, - child: child, - streamChatThemeData: StreamChatThemeData( - colorTheme: ColorTheme.light( - primaryAccent: const Color(0xffffe072), - ), - channelTheme: ChannelTheme( - channelHeaderTheme: ChannelHeaderTheme( - color: const Color(0xffd34646), - title: TextStyle( - color: Colors.white, - ), - ), - ), - ), - ), -``` - -We are creating this class at the very top of our widget tree using the `streamChatThemeData` parameter found in the `StreamChat` widget. - -![](../assets/using_theme.jpg) diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/user_list_view.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/user_list_view.mdx deleted file mode 100644 index 5b11cb2163..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter/user_list_view.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -id: user_list_view -title: UserListView ---- - -A Widget For Displaying And Selecting Users - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/UserListView-class.html) - -![](../assets/user_list_view.png) - -### Background - -A list of users is required for many different purposes: showing a list of users in a Channel, -selecting users to add in a channel, etc. The `UserListView` displays and allows selection of a list -of users along with multiple display configurations like a list and grid. - -### Basic Example - -Let's take a look at an example where we use the widget to autocomplete user names: - -```dart -class UsersListPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - body: UsersBloc( - child: UsersListView( - filter: Filter.notEqual('id', StreamChat.of(context).user!.id), - sort: [ - SortOption( - 'name', - direction: 1, - ), - ], - pagination: PaginationParams( - limit: 25, - ), - ), - ), - ); - } -} -``` - -### Customize The User Items - -You can use your own widget for the user items using the `userItemBuilder` parameter. - -```dart -UsersListView( - // ... - userItemBuilder: (context, user, isSelected) { - return Text(user.name); - }, -), -``` - -### Group Alphabetically - -You can group alphabetically using the `groupAlphabetically` parameter: - -```dart -UsersListView( - //... - groupAlphabetically: true, -), -``` - -### Selecting Users - -The `UserListView` widget allows selecting users in a list by supplying a selected users list and callbacks -for when user items are tapped. - -```dart -Set? selectedUsers = {}; - -UsersListView( - //... - selectedUsers: selectedUsers, - onUserTap: (user, _) { - setState(() { - selectedUsers.add(user); - }); - }, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/_category_.json b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/_category_.json deleted file mode 100644 index 8d738e8937..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Stream Chat Flutter Core", - "position": 4 -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/channel_list_core.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/channel_list_core.mdx deleted file mode 100644 index dce35cc939..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/channel_list_core.mdx +++ /dev/null @@ -1,67 +0,0 @@ ---- -id: channel_list_core -title: ChannelListCore ---- - -A Widget For Building A List Of Channels - -### Background - -The UI SDK of Stream Chat supplies a `ChannelListView` class that builds a list of channels fetching -according to the filters and sort order given. However, in some cases, implementing novel UI is necessary -that cannot be done using the customization approaches given in the widget. - -To do this, we extracted the logic required for fetching channels into a 'Core' widget - a widget that -fetches channels in the expected way via the usual parameters but does not supply any UI and instead -exposes builders to build the UI in situations such as loading, empty data, errors, and on data received. - -### Basic Example - -`ChannelListCore` is a simplified class that allows fetching a list of -channels while exposing UI builders. - -This allows you to construct your own UI while not having to -worry about the specific logic of fetching channels in your app. - -A `ChannelListController` is used to reload and paginate data. - -```dart -class ChannelListPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - body: ChannelListCore( - filter: Filter.in_( - 'members', - [StreamChat.of(context).user!.id], - ), - sort: [SortOption('last_message_at')], - pagination: PaginationParams( - limit: 20, - ), - errorBuilder: (context, err) { - return Center( - child: Text('An error has occured'), - ); - }, - emptyBuilder: (context) { - return Center( - child: Text('Nothing here...'), - ); - }, - loadingBuilder: (context) { - return Center( - child: CircularProgressIndicator(), - ); - }, - listBuilder: (context, list) { - return ChannelPage(list); - } - ), - ); - } -} -``` - -Make sure to have a `StreamChatCore` ancestor in order to provide the -information about the channels. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/channels_bloc.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/channels_bloc.mdx deleted file mode 100644 index ef83cd30d1..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/channels_bloc.mdx +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: channels_bloc -title: ChannelsBloc ---- - -A Widget Dedicated To The Management Of A Channel List With Pagination. - -### Background - -Most widgets in the Core SDK are focused on fetching a particular type of object from Stream Chat - channels, -messages, users, etc. The BLoC widgets bundle up the base functions used to fetch data as well as the current -data fetched by the respective functions. Furthermore, the Core widgets use this BLoC to fetch new or -existing data and build UI based on it. - -All Core and UI widgets which focus on fetching a list of objects need to have their respective functions -above them in the widget tree. The ChannelListCore and ChannelListView require the ChannelsBloc -above them in the widget hierarchy without which they will fail. - -### Understanding The Widget - -`ChannelsBloc` is used together with `ChannelListCore` to manage a list of -Channels with pagination, re-ordering, querying and other operations -associated with Channels. - -`ChannelsBloc` can be accessed at anytime by using the static `.of` method -using Flutter's `BuildContext`. - -```dart -var _channelsBloc = ChannelsBloc.of(context); -``` - -The `ChannelsBloc` widget encapsulates common functionality related to channel lists such as fetching -the existing channels and querying new channels and also supplies them down the widget tree. - -The widget is required for the respective core widget (`ChannelListCore`) to fetch channels and hence -must be above the core widget in the tree. - -Here is a basic implementation of `ChannelsBloc`: - -```dart -ChannelsBloc( - child: // Further Widget Tree -), -``` - -The `ChannelsBloc` widget allows three customisations: - -#### Lock Channels Order - -ChannelsBloc may change the order of channels when new messages arrive. To lock this order, we can -set the `lockChannelsOrder` property to true. - -```dart -ChannelsBloc( - lockChannelsOrder: true, - child: // Further Widget Tree -), -``` - -#### Set custom channel order - -We can decide the order of the channels in the list by supplying a comparator to the `channelsComparator` -parameter: - -```dart -ChannelsBloc( - channelsComparator: (a, b) { - return a.createdAt!.millisecondsSinceEpoch > - b.createdAt!.millisecondsSinceEpoch - ? 1 - : -1; - }, - child: // Further Widget Tree -), -``` - -#### Decide if channel should be added on new message event - -When a new message arrives, a `message.new` event is received. We can decide if we want to add the channel -to the list using the `shouldAddChannel` parameter which is a callback supplying the event data: - -```dart -ChannelsBloc( - shouldAddChannel: (event) { - return event.message!.extraData['priority'] == '1'; - }, - child: // Further Widget Tree -), -``` \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/introduction.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/introduction.mdx deleted file mode 100644 index 6d0b407f79..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/introduction.mdx +++ /dev/null @@ -1,79 +0,0 @@ ---- -id: introduction -title: Introduction ---- - -Understanding The Core Package Of The Flutter SDK - -This package provides business logic to fetch common things required for integrating Stream Chat into your application. -The core package allows more customisation and hence provides business logic but no UI components. -Please use the `stream_chat_flutter` package for the full fledged suite of UI components or `stream_chat` for the low-level client. - -### Background - -In the early days of the Flutter SDK, the SDK was only split into the LLC (`stream_chat`) and -the UI package (`stream_chat_flutter`). With this you could use a fully built interface with the UI package -or a fully custom interface with the LLC. However, we soon recognised the need for a third intermediary -package which made tasks like building and modifying a list of channels or messages easy but without -the complexity of using low level components. The Core package (`stream_chat_flutter_core`) is a manifestation -of the same idea and allows you to build an interface with Stream Chat without having to deal with -low level code and architecture as well as implementing your own theme and UI effortlessly. -Also, it has very few dependencies. - -We will now explore the components of this intermediary package and understand how it helps you build -the experience you want your users to have. - -The package primarily contains three types of classes: - -* Business Logic Components -* Core Components -* Core Controllers - -### Business Logic Components - -These components allow you to have the maximum and lower-level control of the queries being executed. - -In BLoCs, the basic functionalities - such as queries for messages, channels or queries - are bundled up -and passed along down the tree. Using a BLoC allows you to either create your own way to fetch and -build UIs or use an inbuilt Core widget to do the work such as queries, pagination, etc for you. - -The BLoCs we provide are: - -* ChannelsBloc -* MessageSearchBloc -* UsersBloc - -### Core Components - -Core components usually are an easy way to fetch data associated with Stream Chat. -Core components use functions exposed by the respective BLoCs (for example the ChannelListCore uses the ChannelsBloc) -and use the respective controllers for various operations. Unlike heavier components from the UI -package, core components are decoupled from UI and they expose builders instead to help you build -a fully custom interface. - -Data fetching can be controlled with the controllers of the respective core components. - -* ChannelListCore (Fetch a list of channels) -* MessageListCore (Fetch a list of messages from a channel) -* MessageSearchListCore (Fetch a list of search messages) -* UserListCore (Fetch a list of users) -* StreamChatCore (This is different from the other core components - it is a version of StreamChat decoupled from theme and initialisations.) - -### Core Controllers - -Core Controllers are supplied to respective CoreList widgets which allows reloading and pagination of data whenever needed. - -Unlike the UI package, the Core package allows a fully custom user interface built with the data. This -in turn provides a few challenges: we do not know implicitly when to paginate your list or reload your data. - -While this is handled out of the box in the UI package since the List implementation is inbuilt, a controller -needs to be used in the core package notifying the core components to reload or paginate the data existing -currently. For this, each core component has a respective controller which you can use to call the -specific function (reload / paginate) whenever such an event is triggered through / needed in your UI. - -* ChannelListController -* MessageListController -* MessageSearchListController -* ChannelListController - -This section goes into the individual core package widgets and their functional use. diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/message_list_core.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/message_list_core.mdx deleted file mode 100644 index 2ccd6e90aa..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/message_list_core.mdx +++ /dev/null @@ -1,69 +0,0 @@ ---- -id: message_list_core -title: MessageListCore ---- - -A Widget For Building A List Of Messages - -### Background - -The UI SDK of Stream Chat supplies a `MessageListView` class that builds a list of channels fetching -according to the filters and sort order given. However, in some cases, implementing novel UI is necessary -that cannot be done using the customization approaches given in the widget. - -To do this, we extracted the logic required for fetching channels into a 'Core' widget - a widget that -fetches channels in the expected way via the usual parameters but does not supply any UI and instead -exposes builders to build the UI in situations such as loading, empty data, errors, and on data received. - -### Basic Example - -`MessageListCore` is a simplified class that allows fetching a list of -messages while exposing UI builders. - -This allows you to construct your own UI while not having to -worry about the specific logic of fetching messages in a channel. - -A `MessageListController` is used to paginate data. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Column( - children: [ - Expanded( - child: MessageListCore( - emptyBuilder: (context) { - return Center( - child: Text('Nothing here...'), - ); - }, - loadingBuilder: (context) { - return Center( - child: CircularProgressIndicator(), - ); - }, - messageListBuilder: (context, list) { - return MessagesPage(list); - }, - errorWidgetBuilder: (context, err) { - return Center( - child: Text('Error'), - ); - }, - ), - ), - ], - ), - ); - } -} -``` - -Make sure to have a `StreamChannel` ancestor in order to provide the -information about the channels. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/message_search_bloc.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/message_search_bloc.mdx deleted file mode 100644 index c220236004..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/message_search_bloc.mdx +++ /dev/null @@ -1,39 +0,0 @@ ---- -id: message_search_list_block -title: MessageSearchListBloc ---- - -A Widget Used To Manage A List Of Messages With Pagination. - -### Background - -Most widgets in the Core SDK are focused on fetching a particular type of object from Stream Chat - channels, -messages, users etc. The BLoC widgets bundle up the base functions used to fetch data as well as the current -data fetched by the respective functions. Furthermore, the Core widgets use this BLoC to fetch new or -existing data and build UI based on it. - -All Core and UI widgets which focus on fetching a list of objects need to have their respective functions -above them in the widget tree. The MessageSearchListCore and MessageSearchListView require the -MessageSearchListCore above them in the widget hierarchy without which they will fail. - -### Understanding The Widget - -This class can be used to load messages, perform queries, etc. - -`MessageSearchBloc` can be accessed at anytime by using the static `.of` method -using Flutter's BuildContext. - -```dart -var _searchBloc = MessageSearchBloc.of(context); -``` - -The `MessageSearchBloc` widget encapsulates common functionality related to searching for messages -across channels and also supplies them down the widget tree. - -Here is a basic implementation of `ChannelsBloc`: - -```dart -MessageSearchBloc( - child: // Further Widget Tree -), -``` \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/message_search_list_core.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/message_search_list_core.mdx deleted file mode 100644 index f0476e429a..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/message_search_list_core.mdx +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: message_search_list_core -title: MessageSearchListCore ---- - -A Widget For Displaying Message Searches - -### Background - -The UI SDK of Stream Chat supplies a `MessageSearchListView` class that builds a list of channels fetching -according to the filters and sort order given. However, in some cases, implementing novel UI is necessary -that cannot be done using the customization approaches given in the widget. - -To do this, we extracted the logic required for fetching channels into a 'Core' widget - a widget that -fetches channels in the expected way via the usual parameters but does not supply any UI and instead -exposes builders to build the UI in situations such as loading, empty data, errors, and on data received. - -### Basic Example - -`MessageSearchListCore` is a simplified class that allows searching for - messages across channels while exposing UI builders. - A `MessageSearchListController` is used to load and paginate data. - -```dart -class MessageSearchPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - body: MessageSearchListCore( - messageQuery: _messageFilter, - filters: _channelsFilter, - limit: 20, - ), - ); - } -} -``` - -Make sure to have a `MessageSearchBloc` ancestor in order to provide the -information about the messages. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/setup.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/setup.mdx deleted file mode 100644 index f297484274..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/setup.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -id: setup -title: Setup ---- - -Understanding Setup For `stream_chat_flutter_core` - -### Add pub.dev dependency - -First, you need to add the `stream_chat_flutter_core` dependency to your pubspec.yaml - -You can either run this command: - -```shell -flutter pub add stream_chat_flutter_core -``` - -OR - -Add this line in the dependencies section of your pubspec.yaml after substituting latest version: - -```yaml -dependencies: - stream_chat_flutter_core: ^latest_version -``` - -You can find the package details on [pub.dev](https://pub.dev/packages/stream_chat_flutter_core). diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/stream_chat_core.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/stream_chat_core.mdx deleted file mode 100644 index aa7445f93d..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/stream_chat_core.mdx +++ /dev/null @@ -1,25 +0,0 @@ ---- -id: stream_chat_core -title: StreamChatCore ---- - -`StreamChatCore` is a version of `StreamChat` found in `stream_chat_flutter` that is decoupled from -theme and initialisations. - -`StreamChatCore` is used to provide information about the chat client to the widget tree. -This Widget is used to react to life cycle changes and system updates. -When the app goes into the background, the web socket connection is automatically closed and when it goes back to foreground the connection is opened again. - -Like the `StreamChat` widget in the higher level UI package, the `StreamChatCore` widget should -be on the top level before using any Stream functionality: - -```dart -return MaterialApp( - title: 'Stream Chat Core Example', - home: HomeScreen(), - builder: (context, child) => StreamChatCore( - client: client, - child: child!, - ), - ); -``` diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/user_list_core.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/user_list_core.mdx deleted file mode 100644 index 54def8a777..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/user_list_core.mdx +++ /dev/null @@ -1,63 +0,0 @@ ---- -id: user_list_core -title: UserListCore ---- - -A Widget For Building A List Of Users - -### Background - -The UI SDK of Stream Chat supplies a `UserListView` class that builds a list of channels fetching -according to the filters and sort order given. However, in some cases, implementing novel UI is necessary -that cannot be done using the customization approaches given in the widget. - -To do this, we extracted the logic required for fetching channels into a 'Core' widget - a widget that -fetches channels in the expected way via the usual parameters but does not supply any UI and instead -exposes builders to build the UI in situations such as loading, empty data, errors, and on data received. - -### Basic Example - -`UserListCore` is a simplified class that allows fetching users while -exposing UI builders. -A `UserListController` is used to load and paginate data. - -```dart -class UsersListPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - body: UsersListCore( - sort: [SortOption('last_active')], - pagination: PaginationParams( - limit: 20, - ), - errorBuilder: (err) { - return Center( - child: Text('An error has occured'), - ); - }, - emptyBuilder: (context) { - return Center( - child: Text('Nothing here...'), - ); - }, - emptyBuilder: (context) { - return Center( - child: CircularProgressIndicator(), - ); - }, - listBuilder: (context, list) { - return UsersPage(list); - } - ), - ); - } -} -``` - -`UsersBloc` must be the ancestor of this widget. This is necessary since -`UserListCore` depends on functionality contained within `UsersBloc`. - -The parameters `listBuilder`, `loadingBuilder`, `emptyBuilder` and -`errorBuilder` must all be supplied and not null. - diff --git a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/users_bloc.mdx b/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/users_bloc.mdx deleted file mode 100644 index 063d59c7e6..0000000000 --- a/docusaurus/flutter_versioned_docs/version-3.x.x/Flutter/stream_chat_flutter_core/users_bloc.mdx +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: users_bloc -title: UsersBloc ---- - -A Widget Dedicated To The Management Of A Users List With Pagination. - -### Background - -Most widgets in the Core SDK are focused on fetching a particular type of object from Stream Chat - channels, -messages, users, etc. The BLoC widgets bundle up the base functions used to fetch data as well as the current -data fetched by the respective functions. Furthermore, the Core widgets use this BLoC to fetch new or -existing data and build UI based on it. - -All Core and UI widgets which focus on fetching a list of objects need to have their respective functions -above them in the widget tree. The UserListCore and UserListView require the UserListCore -above them in the widget hierarchy without which they will fail. - -### Understanding The Widget - -`UsersBloc` can be accessed at anytime by using the static `.of` method -using Flutter's `BuildContext`. - -```dart -var _userBloc_ = UsersBloc.of(context); -``` - -The `UsersBloc` widget encapsulates common functionality related to user lists and also supplies them down the widget tree. - -Here is a basic implementation of `UsersBloc`: - -```dart -UsersBloc( - child: // Further Widget Tree -), -``` \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/authentication_demo_app.jpg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/authentication_demo_app.jpg deleted file mode 100644 index eed57c3374..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/authentication_demo_app.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_header.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_header.png deleted file mode 100644 index 98f41c614b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_header.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_header_custom_title.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_header_custom_title.png deleted file mode 100644 index 65a9ee75a6..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_header_custom_title.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_list_header.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_list_header.png deleted file mode 100644 index 6f112db9be..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_list_header.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_list_header_custom_subtitle.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_list_header_custom_subtitle.png deleted file mode 100644 index 3c7798570a..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_list_header_custom_subtitle.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_list_view.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_list_view.png deleted file mode 100644 index a4390c2eac..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_preview.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_preview.png deleted file mode 100644 index 39f5629bb8..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/channel_preview.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/chat_basics.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/chat_basics.png deleted file mode 100644 index 82e27cfa49..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/chat_basics.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png deleted file mode 100644 index 9e92437dbf..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/dashboard_firebase_enable.jpeg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/dashboard_firebase_enable.jpeg deleted file mode 100644 index e4696ec882..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/dashboard_firebase_enable.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/dashboard_firebase_key.jpeg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/dashboard_firebase_key.jpeg deleted file mode 100644 index 87243e91f6..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/dashboard_firebase_key.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/dashboard_save_changes.jpeg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/dashboard_save_changes.jpeg deleted file mode 100644 index 1c58a93e63..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/dashboard_save_changes.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/end_to_end_encryption.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/end_to_end_encryption.png deleted file mode 100644 index b41e11ced6..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/end_to_end_encryption.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/firebase_authentication_dashboard.jpg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/firebase_authentication_dashboard.jpg deleted file mode 100644 index c304055768..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/firebase_authentication_dashboard.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png deleted file mode 100644 index c5670d0dc2..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/firebase_project_settings.jpeg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/firebase_project_settings.jpeg deleted file mode 100644 index 4fbc6521c3..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/firebase_project_settings.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/hashtag_example.jpg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/hashtag_example.jpg deleted file mode 100644 index a2bb3ba4c9..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/hashtag_example.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/live_stream_1.jpg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/live_stream_1.jpg deleted file mode 100644 index bef68c6edb..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/live_stream_1.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/live_stream_2.jpg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/live_stream_2.jpg deleted file mode 100644 index 02a3513297..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/live_stream_2.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/localization_support.jpg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/localization_support.jpg deleted file mode 100644 index 50d8b761ee..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/localization_support.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/location_sharing_example.jpg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/location_sharing_example.jpg deleted file mode 100644 index 7f220379c9..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/location_sharing_example.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/location_sharing_example_message.jpg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/location_sharing_example_message.jpg deleted file mode 100644 index 707f138876..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/location_sharing_example_message.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/location_sharing_example_message_thumbnail.jpg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/location_sharing_example_message_thumbnail.jpg deleted file mode 100644 index e2b7d624f5..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/location_sharing_example_message_thumbnail.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_actions.jpg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_actions.jpg deleted file mode 100644 index dcfba64ec2..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_actions.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_input.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_input.png deleted file mode 100644 index d63cfbb3e2..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_input.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_input_change_position.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_input_change_position.png deleted file mode 100644 index 859107d25b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_input_change_position.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_input_quoted_message.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_input_quoted_message.png deleted file mode 100644 index c1fda2237b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_input_quoted_message.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_list_view.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_list_view.png deleted file mode 100644 index cc27be3c9b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_list_view_pin.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_list_view_pin.png deleted file mode 100644 index 0b6f1c391f..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_list_view_pin.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_list_view_threads.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_list_view_threads.png deleted file mode 100644 index 2c9387663f..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_list_view_threads.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_reaction_theming.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_reaction_theming.png deleted file mode 100644 index 8cddd6ba22..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_reaction_theming.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_rounded_avatar.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_rounded_avatar.png deleted file mode 100644 index ec3733443a..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_rounded_avatar.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_search_list_view.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_search_list_view.png deleted file mode 100644 index b13f5bdc95..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_search_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_styles.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_styles.png deleted file mode 100644 index db04865c05..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_styles.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_theming.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_theming.png deleted file mode 100644 index b5d28dde0a..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_theming.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_widget_actions.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_widget_actions.png deleted file mode 100644 index e835a4ed04..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/message_widget_actions.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/sdk_title.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/sdk_title.png deleted file mode 100644 index 4d92e89142..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/sdk_title.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/server_key.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/server_key.png deleted file mode 100644 index f11d6fb56b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/server_key.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/slidable_demo.jpg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/slidable_demo.jpg deleted file mode 100644 index 4cbda5d738..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/slidable_demo.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/stream_chat_user_database.jpg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/stream_chat_user_database.jpg deleted file mode 100644 index fcfe73c82c..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/stream_chat_user_database.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/swipe_channel.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/swipe_channel.png deleted file mode 100644 index 44f13ca594..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/swipe_channel.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/user_list_view.png b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/user_list_view.png deleted file mode 100644 index 9aede8243d..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/user_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/using_theme.jpg b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/using_theme.jpg deleted file mode 100644 index b835d9316d..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/assets/using_theme.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/basics/_category_.json b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/basics/_category_.json deleted file mode 100644 index 76d335692d..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/basics/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Introduction", - "position": 1 -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/basics/choose_package.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/basics/choose_package.mdx deleted file mode 100644 index b7ddf6a6ef..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/basics/choose_package.mdx +++ /dev/null @@ -1,54 +0,0 @@ ---- -id: choose_package -title: Choosing The Right Flutter Package ---- - -### Why the SDK is split into different packages - -Different applications need different levels of customization and integration with the Stream Chat SDK. -To do this, the Flutter SDK is split into three different packages which build upon the last and give -varying levels of control to the developer. The higher level packages offer better compatibility out of the -box while the lower level SDKs offer fine grained control. There is also a separate package for persistence -which allows you persist data locally which works with all packages. - -### How do I choose? - -#### The case for `stream_chat_flutter` - -For the quickest way to integrate Stream Chat with your app, the UI SDK (`stream_chat_flutter`) is the -way to go. `stream_chat_flutter` contains prebuilt components that manage most operations like data -fetching, pagination, sending a message, and more. This ensures you have a nearly out-of-the-box -experience adding chat to your applications. It is also possible to use this in conjunction with -lower level operations of the SDK to get the best of both worlds. - -:::note -The package allows customization of components to a large extent making it easy to tweak the theme -to match your app colors and such. If you require any additional feature or customization, feel free -to request this through our support channels. -::: - -Summary: - -For the quickest and easiest way to add Chat to your app with prebuilt UI components, use `stream_chat_flutter` - - -#### The case for `stream_chat_flutter_core` - -If your application involves UI that does not fit in with the `stream_chat_flutter` components, `stream_chat_flutter_core` -strips away the UI associated with the components and provides the data fetching and manipulation -capabilities while supplying builders for UI. This allows you to implement your own UI and themes -completely independently while not worrying about writing functions for data and pagination. - -Summary: - -For implementing your own custom UI while not having to worry about lower level API calls, use `stream_chat_flutter_core`. - -#### The case for `stream_chat` - -The `stream_chat` package is the Low-level Client (LLC) of Stream Chat in Flutter. This package wraps -the underlying functionality of Stream Chat and allows the most customization in terms of UI, data, -and architecture. - -Summary: - -For the most control over the SDK and dealing with low level calls to the API, use `stream_chat`. diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/basics/introduction.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/basics/introduction.mdx deleted file mode 100644 index 296a2d7f8c..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/basics/introduction.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -slug: / -id: introduction -title: About The Flutter SDK ---- -Exploring The Basics Of Stream Chat - -![](../assets/sdk_title.png) - -Stream Chat is a service that helps you easily build a full chat experience in your Flutter apps. -We also support a variety of other SDKs. - -This section of the documentation focuses on our Flutter SDK which helps you easily -ship high quality messaging experiences in apps and programs built with the [Flutter toolkit -made by Google](https://flutter.dev). - -The Stream Chat Flutter SDK comprises five different packages to choose from, ranging from ones -giving you complete control to ones that give you a rich out-of-the-box chat experience. - -The packages that make up the Stream Chat SDK are: - -1. Low Level Client (stre`am_chat): a pure Dart package that can be used on any Dart project. -It provides a low-level client to access the Stream Chat service. -2. Core (`stream_chat_flutter_core`): provides business logic to fetch common things required -for integrating Stream Chat into your application. -The core package allows more customisation and hence provides business logic but no UI components. -3. UI (`stream_chat_flutter`): this library includes both a low-level chat SDK and a set of -reusable and customizable UI components. -4. Persistence (`stream_chat_persistence`): provides a persistence client for fetching and -saving chat data locally. -5. Localizations (`stream_chat_localizations`): provides a set of localizations for the SDK. - -We recommend building prototypes using the full UI package, [`stream_chat_flutter`](https://pub.dev/packages/stream_chat_flutter), -since it contains UI widgets already integrated with Stream's API. It is the fastest way to get up -and running using Stream chat in your app. - -The Flutter SDK enables you to build any type of chat or messaging experience for Android, iOS, Web -and Desktop. - -If you're building a very custom UI and would prefer a more lean package, -[`stream_chat_flutter_core`](https://pub.dev/packages/stream_chat_flutter_core) will be suited to this -use case. Core allows you to build custom, expressive UIs while retaining the benefits of our full -Flutter SDK. APIs for accessing and controlling users, sending messages, and so forth are seamlessly integrated -into this package and accessible via providers and builders. - -Before going into the docs, let's take a small detour to look at how the elements of Stream Chat are structured. - -### Basic Structure - -There are two core elements in chat, Users and Channels. -Channels are groups of one or more users that can message each other. -In an app, you need to have a user connected to query channels. - -There is no specific distinction between a chat with only two people and a group chat, -but there is a way to create a unique chat between a certain number of people by creating a distinct channel. - -![](../assets/chat_basics.png) - -In essence, a normal two-person chat would be a distinct channel created with two members (you cannot add or delete members in this channel), whereas a group created with two people would simply be a non distinct channel (possible to add or remove members). - -:::note -It is also possible to add more than two people in a distinct channel which retains the same add/removal properties and resembles the Slack DMs where you can DM one or more people as well. -::: - -In summary, if you were creating a Whatsapp-like app, the first screen would be a list of channels - which on opening would show a list of messages that were sent by the users in the Channel. - -While this is a simplistic overview of the service, the Flutter SDK handles the UI and more time consuming things (media upload, offline storage, theming, etc.) for you. - -Before reading the docs, consider trying our [online API tour](https://getstream.io/chat/get_started/), -it is a nice way to learn how the API works. -It's in-browser so you'll need to use JavaScript but the core concepts are pretty much the same as Dart. - -You may also like to look at the [Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) -which focuses on using the UI package to get Stream Chat integrated into a Flutter app. - -Further sections break down each individual packages and explain several common operations. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/basics/versioning_policy.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/basics/versioning_policy.mdx deleted file mode 100644 index 9f50c98f9e..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/basics/versioning_policy.mdx +++ /dev/null @@ -1,19 +0,0 @@ ---- -id: versioning_policy -title: Versioning Policy ---- - -All of the Stream Chat packages follow [semantic versioning](https://semver.org/). - -That means that with a version number x.y.z (major.minor.patch): -- When releasing bug fixes (backwards compatible), we make a patch release by changing the z number (ex: 3.6.2 to 3.6.3). A bug fix is defined as an internal change that fixes incorrect behavior. -- When releasing new features or non-critical fixes, we make a minor release by changing the y number (ex: 3.6.2 to 3.7.0). -- When releasing breaking changes (backward incompatible), we make a major release by changing the x number (ex: 3.6.2 to 4.0.0). - -See the [semantic versioning](https://dart.dev/tools/pub/versioning#semantic-versions) section from the Dart docs for more information. - -This versioning policy does not apply to prerelease packages (below major version of 1). See this -[StackOverflow thread](https://stackoverflow.com/questions/66201337/how-do-dart-package-versions-work-how-should-i-version-my-flutter-plugins) -for more information on Dart package versioning. - -Whenever possible, we will add deprecation warnings in preparation for future breaking changes. diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/_category_.json b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/_category_.json deleted file mode 100644 index cb58ac0dc4..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Guides", - "position": 2 -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_chat_to_video_livestreams.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_chat_to_video_livestreams.mdx deleted file mode 100644 index 78cf8f8889..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_chat_to_video_livestreams.mdx +++ /dev/null @@ -1,97 +0,0 @@ ---- -id: adding_chat_to_video_livestreams -title: Adding Chat To Video Livestreams ---- - -Adding Chat To Video Livestreams - -### Introduction - -Video livestreams are usually complemented with a chat section to make the livestream more interactive -and encourage retention. There are several ways to show the chat interface on the screen and requires -some design choices. - -This guide details multiple ways of adding chat functionality to your video livestream. - -### Implementing Chat - -There are two common scenarios in live-streaming applications depending how well integrated the two -components (video + chat) are allowed to be on the screen. Two common types are split-screen and a -chat overlay that fades in. - -Let's explore creating both types: - -### Split-screen - -In the split-screen implementation, we have a visual split between the video and the message list. -This allows the content to be unobstructed by chat and have a clear separation of boundaries. - -![](../assets/live_stream_1.jpg) - -```dart -Scaffold( - body: Column( - children: [ - Expanded( - child: // Your video implementation here, - ), - Expanded( - child: Column( - children: [ - Expanded( - child: StreamMessageListView(), - ), - StreamMessageInput(), - ], - ), - ), - ], - ), -) -``` - -### Overlapping chat with a transparency gradient - -Another way to add chat is to overlay the video content with messages which progressively fade out -as we go to the top of the screen. This gives the content a more rich feel as it takes the whole -screen and allows the chat to be more homogeneously integrated with the content. - -The second type looks like this: - -![](../assets/live_stream_2.jpg) - -We can use a `Stack` for achieving this: - -```dart -Stack( - children: [ - // Add your video implementation here - ShaderMask( - shaderCallback: (rect) { - return const LinearGradient( - begin: Alignment.bottomCenter, - end: Alignment.topCenter, - colors: [Colors.black, Colors.transparent], - stops: [0.4, 0.8]).createShader( - Rect.fromLTRB(0, 0, rect.width, rect.height), - ); - }, - blendMode: BlendMode.dstIn, - child: Column( - children: const [ - Expanded( - child: StreamMessageListViewTheme( - data: StreamMessageListViewThemeData( - backgroundColor: Colors.transparent, - ), - child: StreamMessageListView(), - ), - ), - StreamMessageInput(), - ], - ), - ), - ], -), -``` - diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_custom_attachments.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_custom_attachments.mdx deleted file mode 100644 index ddc43904ba..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_custom_attachments.mdx +++ /dev/null @@ -1,263 +0,0 @@ ---- -id: adding_custom_attachments -title: Adding Custom Attachments ---- - -Adding Your Own Types Of Attachments To A Message - -### Introduction - -Stream Chat supports attachment types like images, video and files by default. You can also add your -own types of attachments through the SDK such as location, audio, etc. - -This involves doing three things: - -1) Rendering the attachment thumbnail in the `StreamMessageInput` - -2) Sending a message with the custom attachment - -3) Rendering the custom message attachment - -To do this, let's check out an example to add location sharing to Stream Chat. - -### Location Sharing - -Let's build an example of location sharing option in the app: - -![](../assets/location_sharing_example.jpg) - -* Show a "Share Location" button next to StreamMessageInput `Textfield`. - -* When the user presses this button, it should fetch the current location coordinates of the user, and send a message on the channel as follows: - -```dart -Message( - text: 'This is my location', - attachments: [ - Attachment( - uploadState: UploadState.success(), - type: 'location', - extraData: { - 'latitude': 'fetched_latitude', - 'longitude': 'fetched_longitude', - }, - ), - ], -) -``` - -For our example, we are going to use [`geolocator`](https://pub.dev/packages/geolocator) library. -Please check their [setup instructions](https://pub.dev/packages/geolocator) on their docs. - -NOTE: If you are testing on iOS simulator, you will need to set some dummy coordinates, as mentioned [here](https://stackoverflow.com/a/31238119/7489541). -Also don't forget to enable "location update" capability in background mode, from XCode. - -On the receiver end, `location` type attachment should be rendered in map view, in the `StreamMessageListView`. -We are going to use [Google Static Maps API](https://developers.google.com/maps/documentation/maps-static/overview) to render the map in the message. -You can use other libraries as well such as [`google_maps_flutter`](https://pub.dev/packages/google_maps_flutter). - -First, we add a button which when clicked fetches and shares location into the `MessageInput`: - -```dart -StreamMessageInput( - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20.0, - color: StreamChatTheme.of(context).colorTheme.grey, - ), - onTap: () { - var channel = StreamChannel.of(context).channel; - var user = StreamChat.of(context).user; - - _determinePosition().then((value) { - channel.sendMessage( - Message( - text: 'This is my location', - attachments: [ - Attachment( - uploadState: UploadState.success(), - type: 'location', - extraData: { - 'latitude': value.latitude.toString(), - 'longitude': value.longitude.toString(), - }, - ), - ], - ), - ); - }).catchError((err) { - print('Error getting location!'); - }); - }, - ), - ], -), - -Future _determinePosition() async { - bool serviceEnabled; - LocationPermission permission; - - serviceEnabled = await Geolocator.isLocationServiceEnabled(); - if (!serviceEnabled) { - return Future.error('Location services are disabled.'); - } - - permission = await Geolocator.checkPermission(); - if (permission == LocationPermission.denied) { - permission = await Geolocator.requestPermission(); - if (permission == LocationPermission.deniedForever) { - return Future.error( - 'Location permissions are permanently denied, we cannot request permissions.'); - } - - if (permission == LocationPermission.denied) { - return Future.error( - 'Location permissions are denied'); - } - } - - return await Geolocator.getCurrentPosition(); -} -``` - -Next, we build the Static Maps URL (Add your API key before using the code snippet): - -```dart - String _buildMapAttachment(String lat, String long) { - var baseURL = 'https://maps.googleapis.com/maps/api/staticmap?'; - var url = Uri( - scheme: 'https', - host: 'maps.googleapis.com', - port: 443, - path: '/maps/api/staticmap', - queryParameters: { - 'center': '${lat},${long}', - 'zoom': '15', - 'size': '600x300', - 'maptype': 'roadmap', - 'key': 'YOUR_API_KEY', - 'markers': 'color:red|${lat},${long}' - }); - - return url.toString(); - } -``` - -And then modify the `StreamMessageListView` and tell it how to build a location attachment, using the `messageBuilder` property and copying the default message implementation overriding the `customAttachmentBuilders` property: - -```dart -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - customAttachmentBuilders: { - 'location': (context, message, attachments) { - final attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'], - attachments[0].extraData['longitude'], - ), - ); - - return wrapAttachmentWidget(context, attachmentWidget, null, true, BorderRadius.circular(8.0)); - } - }, - ); - }, -), -``` - -This gives us the final location attachment: - -![](../assets/location_sharing_example_message.jpg) - -Additionally, you can also add a thumbnail if a message has a location attachment (unlike in this case, where we sent the message directly). - -To do this, we will: - -1) Add an attachment instead of sending a message - -2) Customize the `StreamMessageInput` - -First, we add the attachment when the location button is clicked: - -```dart - StreamMessageInputController _messageInputController = StreamMessageInputController(); - - StreamMessageInput( - messageInputController: _messageInputController, - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20.0, - color: StreamChatTheme.of(context).colorTheme.grey, - ), - onTap: () { - _determinePosition().then((value) { - _messageInputController.addAttachment( - Attachment( - uploadState: UploadState.success(), - type: 'location', - extraData: { - 'latitude': value.latitude.toString(), - 'longitude': value.longitude.toString(), - }, - ), - ); - }).catchError((err) { - print('Error getting location!'); - }); - }, - ), - ], - ), -``` - -After this, we can build the thumbnail: - -```dart -StreamMessageInput( - messageInputController: _messageInputController, - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20.0, - color: StreamChatTheme.of(context).colorTheme.grey, - ), - onTap: () { - _determinePosition().then((value) { - _messageInputController.addAttachment( - Attachment( - uploadState: UploadState.success(), - type: 'location', - extraData: { - 'latitude': value.latitude.toString(), - 'longitude': value.longitude.toString(), - }, - ), - ); - }).catchError((err) { - print('Error getting location!'); - }); - }, - ), - ], - attachmentThumbnailBuilders: { - 'location': (context, attachment) { - return Image.network( - _buildMapAttachment( - attachment.extraData['latitude'], - attachment.extraData['longitude'], - ), - ); - }, - }, -), -``` - -And we can see the thumbnails in the StreamMessageInput: - -![](../assets/location_sharing_example_message_thumbnail.jpg) diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_local_data_persistence.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_local_data_persistence.mdx deleted file mode 100644 index e9b4909b17..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_local_data_persistence.mdx +++ /dev/null @@ -1,75 +0,0 @@ ---- -id: adding_local_data_persistence -title: Adding Local Data Persistence ---- - -Adding Local Data Persistence - -### Introduction - -Most messaging apps need to work regardless of whether the app is currently connected to the internet. -Local data persistence stores the fetched data from the backend on a local SQLite database using the -moor package in Flutter. All packages in the SDK can use local data persistence to store messages -across multiple platforms. - -### Implementation - -To add data persistence you can extend the class ChatPersistenceClient and pass an instance to the StreamChatClient. - -```dart -class CustomChatPersistentClient extends ChatPersistenceClient { -... -} - -final client = StreamChatClient( - apiKey ?? kDefaultStreamApiKey, - logLevel: Level.INFO, -)..chatPersistenceClient = CustomChatPersistentClient(); -``` - -We provide an official persistent client in the [`stream_chat_persistence`](https://pub.dev/packages/stream_chat_persistence) -package that works using the library [moor](https://moor.simonbinder.eu), an SQLite ORM. - -Add this to your package's `pubspec.yaml` file, using the latest version. - -```yaml -dependencies: - stream_chat_persistence: ^latest_version -``` - -You should then run `flutter packages get` - -The usage is pretty simple. - -1. Create a new instance of `StreamChatPersistenceClient` providing `logLevel` and `connectionMode` - -```dart -final chatPersistentClient = StreamChatPersistenceClient( - logLevel: Level.INFO, - connectionMode: ConnectionMode.background, -); -``` - -2. Pass the instance to the official `StreamChatClient` - -```dart - final client = StreamChatClient( - apiKey ?? kDefaultStreamApiKey, - logLevel: Level.INFO, - )..chatPersistenceClient = chatPersistentClient; -``` - -And you are ready to go... - -Note that passing `ConnectionMode.background` the database uses a background isolate to unblock the main thread. -The `StreamChatClient` uses the `chatPersistentClient` to synchronize the database with the newest -information every time it receives new data about channels/messages/users. - -### Multi-user - -The DB file is named after the `userId`, so if you instantiate a client using a different `userId` you will use a different database. -Calling `client.disconnectUser(flushChatPersistence: true)` flushes all current database data. - -### Updating/deleting/sending a message while offline - -The information about the action is saved in offline storage. When the client returns online, everything is retried. diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_localization.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_localization.mdx deleted file mode 100644 index a02cd793a9..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_localization.mdx +++ /dev/null @@ -1,190 +0,0 @@ ---- -id: adding_localization -title: Adding Localization (l10n) / Internationalization (i18n) ---- - -Adding Localization To UI Widgets - -### Introduction - -We have a dedicated package for adding localization to our UI widgets. It's called `stream_chat_localizations` and you can find it [here](https://pub.dev/packages/stream_chat_localizations). - -![](../assets/localization_support.jpg) - -## What is Localization? - -If you deploy your app to users who speak another language, you'll need to internationalize (localize) it. That means you need to write the app in a way that makes it possible to localize values like text and layouts for each language or locale that the app supports. For more information, see the [Flutter documentation](https://flutter.dev/docs/development/accessibility-and-localization/internationalization). - -What this package allows you to do is to provide localized strings for the Stream chat widgets. For example, depending on the application locale, the Stream Chat widgets will display the appropriate language. The locale will be set automatically, based on system preferences, or you could set it programmatically in your app. The package supports several different languages, with more to be added. The package allows you to override any supported language or add a new language that isn't supported. - -:::note -If you want to translate messages, or enable automatic translation, please see the [Translation documentation](https://getstream.io/chat/docs/flutter-dart/translation/?language=dart). -::: - -### Supported languages - -At the moment we support the following languages: -- [English](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart) -- [Hindi](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart) -- [Italian](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart) -- [French](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart) -- [Spanish](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart) -- [Japanese](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart) -- [Korean](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart) -More languages will be added in the future. Feel free to [contribute](https://github.com/GetStream/stream-chat-flutter/blob/master/CONTRIBUTING.md) to add more languages. - -### Add dependency - -Add this to your package's `pubspec.yaml` file, use the latest version [![Pub](https://img.shields.io/pub/v/stream_chat_localizations.svg)](https://pub.dartlang.org/packages/stream_chat_localizations) -```yaml -dependencies: - stream_chat_localizations: ^latest_version -``` - -Then run `flutter packages get` - -### Usage - -Generally, Flutter and the Stream Chat SDK will use the system locale of the user's device, if that locale is supported (see below). If the locale is not supported we will default to `en` (however it's always possible to [customize that](#changing-the-default-language)). -Make sure to read more about localization in the [official Flutter docs](https://flutter.dev/docs/development/accessibility-and-localization/internationalization). - -```dart -import 'package:flutter/material.dart'; -import 'package:stream_chat_localizations/stream_chat_localizations.dart'; - -void main() { - WidgetsFlutterBinding.ensureInitialized(); - runApp(MyApp()); -} - -class MyApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - return MaterialApp( - // Add all the supported locales - supportedLocales: const [ - Locale('en'), - Locale('hi'), - Locale('fr'), - Locale('it'), - Locale('es'), - Locale('ja'), - Locale('ko'), - ], - // Add GlobalStreamChatLocalizations.delegates - localizationsDelegates: GlobalStreamChatLocalizations.delegates, - builder: (context, widget) => StreamChat( - client: client, - child: widget, - ), - home: StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ); - } -} -``` - -## Setting a language -The application language can be changed through system preferences or programmatically. - -### System Preferences -The application locale can be changed by changing the language for your device or emulator within the device's system preferences. - -[iOS change language](https://support.apple.com/en-us/HT204031) - -[Android change language](https://support.google.com/websearch/answer/3333234?co=GENIE.Platform%3DAndroid&hl=en) - -Note that the language needs to be supported in your application to work. - -### Programmatically -You can also set the locale programmatically in your Flutter application without changing the device's language. - -```dart -return MaterialApp( - ... - locale: const Locale('fr'), - ... -); -``` - -There are many ways that this can be set for additional control. For information and examples, see this [Stack Overflow post](https://stackoverflow.com/questions/49441212/flutter-multi-lingual-application-how-to-override-the-locale). - -### Adding a new language - -To add a new language, create a new class extending `GlobalStreamChatLocalizations` and create a delegate for it, adding it to the `delegates` array. - -Check out [this example](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/example/lib/add_new_lang.dart) to see how to add a new language. - -### Override existing languages - -To override an existing language, create a new class extending that particular language class and create a delegate for it, adding it to the `delegates` array. - -Check out [this example](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/example/lib/override_lang.dart) to see how to override an existing language. - -### Changing the default language - -To change the default language you can use the `MaterialApp.localeListResolutionCallback` property. -Here is an example of how that would look like: - -```dart - MaterialApp( - theme: ThemeData.light(), - darkTheme: ThemeData.dark(), - // Add all the supported locales - supportedLocales: const [ - Locale('en'), - Locale('hi'), - Locale('fr'), - Locale('it'), - Locale('es'), - Locale('ja'), - Locale('ko'), - ], - // locales are the locales of the device - // supportedLocales are the app supported locales - localeListResolutionCallback: (locales, supportedLocales) { - // We map the supported locales to language codes - // note that this is completely optional and this logic can be changed as you like - final supportedLanguageCodes = - supportedLocales.map((e) => e.languageCode); - if (locales != null) { - // we iterate over the locales and find the first one that is supported - for (final locale in locales) { - if (supportedLanguageCodes.contains(locale.languageCode)) { - return locale; - } - } - } - - // if we didn't find a supported language, we return the Italian language - return const Locale('it'); - }, - // Add GlobalStreamChatLocalizations.delegates - localizationsDelegates: GlobalStreamChatLocalizations.delegates, - ... - -``` - -In this case, we're using Italian as the default language. - -### ⚠️ Note on **iOS** - -For translation to work on **iOS** you need to add supported locales to -`ios/Runner/Info.plist` as described [here](https://flutter.dev/docs/development/accessibility-and-localization/internationalization#specifying-supportedlocales). - -Example: - -```xml -CFBundleLocalizations - - en - nb - fr - it - es - ja - ko - -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_push_notifications.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_push_notifications.mdx deleted file mode 100644 index fa72779b9d..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_push_notifications.mdx +++ /dev/null @@ -1,262 +0,0 @@ ---- -id: adding_push_notifications -title: Adding Push Notifications (V1 legacy) ---- - -Adding Push Notifications To Your Application - -:::note -Version 1 (legacy) of push notifications won't be removed immediately but there won't be any new features. That's why new applications are highly recommended to use version 2 from the beginning to leverage upcoming new features. -::: - -### Introduction - -Push notifications are a core part of the experience for a messaging app. Users often need to be notified -of new messages and old notifications sometimes need to be updated silently as well. - -This guide details how to add push notifications to your app. - -Make sure to check [this section](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart) of the docs to read about the push delivery logic. - -### Setup FCM - -To integrate push notifications in your Flutter app you need to use the package [`firebase_messaging`](https://pub.dev/packages/firebase_messaging). - - -Follow the [Firebase documentation](https://firebase.flutter.dev/docs/messaging/overview/) to know how to set up the plugin for both Android and iOS. - - -Once that's done FCM should be able to send push notifications to your devices. - -### Integration with Stream - -#### Step 1 - -From the [Firebase Console](https://console.firebase.google.com/), select the project your app belongs to. - -#### Step 2 - -Click on the gear icon next to `Project Overview` and navigate to **Project settings** - -![](../assets/firebase_project_settings.jpeg) - -#### Step 3 - -Navigate to the `Cloud Messaging` tab - -#### Step 4 - -Under `Project Credentials`, locate the `Server key` and copy it - -![](../assets/server_key.png) - -#### Step 5 - -Upload the `Server Key` in your chat dashboard - -![](../assets/dashboard_firebase_enable.jpeg) - -![](../assets/dashboard_firebase_key.jpeg) - - -:::note -We are setting up the Android section, but this will work for both Android and iOS if you're using Firebase for both of them. -::: - -#### Step 6 - -Save your push notification settings changes - -![](../assets/dashboard_save_changes.jpeg) - -**OR** - -Upload the `Server Key` via API call using a backend SDK - -```js -await client.updateAppSettings({ - firebase_config: { - server_key: 'server_key', - notification_template: `{"message":{"notification":{"title":"New messages","body":"You have {{ unread_count }} new message(s) from {{ sender.name }}"},"android":{"ttl":"86400s","notification":{"click_action":"OPEN_ACTIVITY_1"}}}}`, - data_template: `{"sender":"{{ sender.id }}","channel":{"type": "{{ channel.type }}","id":"{{ channel.id }}"},"message":"{{ message.id }}"}` - }, -}); -``` - -### Registering a device at Stream Backend - -Once you configure Firebase server key and set it up on Stream dashboard a device that is supposed to receive push notifications needs to be registered at Stream backend. This is usually done by listening for Firebase device token updates and passing them to the backend as follows: - -```dart -firebaseMessaging.onTokenRefresh.listen((token) { - client.addDevice(token, PushProvider.firebase); -}); -``` - -### Possible issues - - -We only send push notifications when the user doesn't have any active web socket connection (which is established when you call `client.connectUser`). If you set the [onBackgroundEventReceived](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/onBackgroundEventReceived.html) property of the StreamChat widget, when your app goes to background, your device will keep the WS connection alive for 1 minute, and so within this period, you won't receive any push notification. - -Make sure to read the [general push docs](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart) in order to avoid known gotchas that may make your relationship with notifications go bad 😢 - -### Testing if Push Notifications are Setup Correctly - -If you're not sure if you've set up push notifications correctly (for example you don't always receive them, they work unreliably), you can follow these steps to make sure your configuration is correct and working: - -1. Clone our repository for push testing git clone git@github.com:GetStream/chat-push-test.git - -2. `cd flutter` - -3. In folder run `flutter pub get` - -4. Input your API key and secret in `lib/main.dart` - -5. Change the bundle identifier/application ID and development team/user so you can run the app in your device (**do not** run on iOS simulator, Android emulator is fine) - -6. Add your `google-services.json/GoogleService-Info.plist` - -7. Run the app - -8. Accept push notification permission (iOS only) - -9. Tap on `Device ID` and copy it - -10. Send the app to background - -11. After configuring [stream-cli](https://github.com/GetStream/stream-cli) paste the following command on command line using your user ID - -```shell -stream chat:push:test -u -``` - -You should get a test push notification - -### App in the background but still connected - -The [StreamChat](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat-class.html) widget lets you define a [onBackgroundEventReceived](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/onBackgroundEventReceived.html) handler in order to handle events while the app is in the background, but the client is still connected. - -This is useful because it lets you keep the connection alive in cases in which the app goes in the background just for some seconds (for example multitasking, picking pictures from the gallery...) - -You can even customize the [backgroundKeepAlive](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/backgroundKeepAlive.html) duration. - -In order to show notifications in such a case we suggest using the package [`flutter_local_notifications`](https://pub.dev/packages/flutter_local_notifications); follow the package guide to successfully set up the plugin. - -Once that's done you should set the [onBackgroundEventReceived](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/onBackgroundEventReceived.html); here is an example: - -```dart -... -StreamChat( - client: client, - onBackgroundEventReceived: (e) { - final currentUserId = client.state.user.id; - if (![ - EventType.messageNew, - EventType.notificationMessageNew, - ].contains(event.type) || - event.user.id == currentUserId) { - return; - } - if (event.message == null) return; - final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); - final initializationSettingsAndroid = - AndroidInitializationSettings('launch_background'); - final initializationSettingsIOS = IOSInitializationSettings(); - final initializationSettings = InitializationSettings( - android: initializationSettingsAndroid, - iOS: initializationSettingsIOS, - ); - await flutterLocalNotificationsPlugin.initialize(initializationSettings); - await flutterLocalNotificationsPlugin.show( - event.message.id.hashCode, - event.message.user.name, - event.message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'message channel', - 'Message channel', - 'Channel used for showing messages', - priority: Priority.high, - importance: Importance.high, - ), - iOS: IOSNotificationDetails(), - ), - ); - }, - child: .... -); -... -``` - -As you can see we generate a local notification whenever a message.new or notification.message_new event is received. - -### Foreground notifications - -Sometimes you may want to show a notification when the app is in the foreground. -For example, when you're in a channel and you receive a new message from someone in another channel. - -For this scenario, you can also use the `flutter_local_notifications` package to show a notification. - -You need to listen for new events using `StreamChatClient.on` and handle them accordingly. - -Here we're checking if the event is a `message.new` or `notification.message_new` event, and if the message is from a different user than the current user. In that case we'll show a notification. - -```dart -client.on( - EventType.messageNew, - EventType.notificationMessageNew, -).listen((event) { - if (event.message?.user?.id == client.state.currentUser?.id) { - return; - } - showLocalNotification(event, client.state.currentUser!.id, context); -}); -``` - -:::note -You should also check that the channel of the message is different than the channel in the foreground. -How you do this depends on your app infrastructure and how you handle navigation. -Take a look at the [Stream Chat v1 sample app](https://github.com/GetStream/flutter-samples/blob/main/packages/stream_chat_v1/lib/home_page.dart#L11) to see how we're doing it over there. -::: - -### Saving notification messages to the offline storage - -You may want to save received messages when you receive them via a notification so that later on when you open the app they're already there. - -To do this we need to update the push notification data payload at Stream Dashboard and clear the notification one: - -```json -{ - "message_id": "{{ message.id }}", - "channel_id": "{{ channel.id }}", - "channel_type": "{{ channel.type }}" -} -``` - -Then we need to integrate the package [`stream_chat_persistence`](https://pub.dev/packages/stream_chat_persistence) in our app that exports a persistence client, learn [here](https://pub.dev/packages/stream_chat_persistence#usage) how to set it up. - -Then during the call `firebaseMessaging.configure(...)` we need to set the `onBackgroundMessage` parameter using a TOP-LEVEL or STATIC function to handle background messages; here is an example: - -```dart -Future myBackgroundMessageHandler(message) async { - if (message.containsKey('data')) { - final data = message['data']; - final messageId = data['message_id']; - final channelId = data['channel_id']; - final channelType = data['channel_type']; - final cid = '$channelType:$channelId'; - - final client = StreamChatClient(apiKey); - final persistenceClient = StreamChatPersistenceClient(); - await persistenceClient.connect(userId); - - final message = await client.getMessage(messageId).then((res) => res.message); - - await persistenceClient.updateMessages(cid, [message]); - persistenceClient.disconnect(); - - /// This can be done using the package flutter_local_notifications as we did before 👆 - _showLocalNotification(); - } -} -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_push_notifications_v2.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_push_notifications_v2.mdx deleted file mode 100644 index 086d632ec1..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/adding_push_notifications_v2.mdx +++ /dev/null @@ -1,308 +0,0 @@ ---- -id: adding_push_notifications_v2 -title: Adding Push Notifications (V2) ---- - -Adding Push Notifications To Your Application - -### Introduction - -Push notifications are a core part of the experience for a messaging app. Users often need to be notified -of new messages and old notifications sometimes need to be updated silently. - -This guide details how to add push notifications to your app. - -You can read more about Stream’s [push delivery logic](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart#push-delivery-rules). - -### Setup FCM - -To integrate push notifications in your Flutter app, you need to use the package [`firebase_messaging`](https://pub.dev/packages/firebase_messaging). - - -Follow the [Firebase documentation](https://firebase.flutter.dev/docs/messaging/overview/) to set up the plugin for Android and iOS. - - -Once that's done, FCM should be able to send push notifications to your devices. - -### Integration With Stream - -#### Step 1 - Get the Firebase Credentials - -These credentials are the [private key file](https://firebase.google.com/docs/admin/setup#:~:text=To%20generate%20a%20private%20key%20file%20for%20your%20service%20account%3A) 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 which needs to be uploaded to Stream’s server as explained in next step. - -#### Step 2 - Upload the Firebase Credentials to Stream - -You can upload your Firebase credentials using either the dashboard or the app settings API (available only in backend SDKs). - -##### Using the Stream Dashboard - -1. Go to the **Chat Overview** page on Stream Dashboard - -![](../assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png) - -2. Enable **Firebase Notification** toggle on **Chat Overview** - -![](../assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png) - -3. Enter your Firebase Credentials and press `"Save"`. - -##### Using the API - -You can also enable Firebase notifications and upload the Firebase credentials using one of our server SDKs. - -For example, using the JavaScript SDK: - -```js -const client = StreamChat.getInstance('api_key', 'api_secret'); -client.updateAppSettings({ - push_config: { - version: 'v2' - }, - firebase_config: { - credentials_json: fs.readFileSync( - './firebase-credentials.json', - 'utf-8', - ), - }); -``` -### Registering a Device With Stream Backend - -Once you configure a Firebase server key and set it up on Stream dashboard then a device that is supposed to receive push notifications needs to be registered on the Stream backend. This is usually done by listening for Firebase device token updates and passing them to the backend as follows: - -```dart -firebaseMessaging.onTokenRefresh.listen((token) { - client.addDevice(token, PushProvider.firebase); -}); -``` - -Push Notifications v2 also supports specifying a name to the push device tokens you register. By setting the optional `pushProviderName` parameter in the `addDevice` call you can support different configurations between the device and the `PushProvider`. - -```dart -firebaseMessaging.onTokenRefresh.listen((token) { - client.addDevice(token, PushProvider.firebase, pushProviderName: 'my-custom-config'); -}); -``` - -### Receiving Notifications - -Push notifications behave a bit differently depending on whether you are using iOS or Android. -See [here](https://firebase.flutter.dev/docs/messaging/usage#message-types) to understand the difference between **notification** and **data** payloads. - -#### iOS - -On iOS we send both a **notification** and a **data** payload. -This means you don't need to do anything special to get the notification to show up. However, you might want to handle the data payload to perform some logic when the user taps on the notification. - -To update the template, you can use a backend SDK. -For example, using the JavaScript SDK: - -```js -const client = StreamChat.getInstance(‘api_key’, ‘api_secret’); -const apn_template = `{ - "aps": { - "alert": { - "title": "New message from {{ sender.name }}", - "body": "{{ truncate message.text 2000 }}" - }, - "mutable-content": 1, - "category": "stream.chat" - }, - "stream": { - "sender": "stream.chat", - "type": "message.new", - "version": "v2", - "id": "{{ message.id }}", - "cid": "{{ channel.cid }}" - } -}`; - -client.updateAppSettings({ - firebase_config: { - apn_template, - }); -``` - -#### Android -On Android we send only a **data** payload. This gives you more flexibility and lets you decide what to do with the notification. - -For example, you can listen and generate a notification from them. - -To generate a notification when a **data-only** message is received and the app is in background: - -```dart -Future onBackgroundMessage(RemoteMessage message) async { - final chatClient = StreamChatClient(apiKey); - - chatClient.connectUser( - User(id: userId), - userToken, - connectWebSocket: false, - ); - - handleNotification(message, chatClient); -} - -void handleNotification( - RemoteMessage message, - StreamChatClient chatClient, -) async { - - final data = message.data; - - if (data['type'] == 'message.new') { - final flutterLocalNotificationsPlugin = await setupLocalNotifications(); - final messageId = data['id']; - final response = await chatClient.getMessage(messageId); - - flutterLocalNotificationsPlugin.show( - 1, - 'New message from ${response.message.user.name} in ${response.channel.name}', - response.message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'new_message', - 'New message notifications channel', - )), - ); - } -} - -FirebaseMessaging.onBackgroundMessage(onBackgroundMessage); -``` - -In the above example, you get the message details using the `getMessage` method and then you use the [`flutter_local_notifications`](https://pub.dev/packages/flutter_local_notifications) package to show the actual notification. - -##### Using a Template on Android - -It's still possible to add a **notification** payload to Android notifications. -You can do so by adding a template using a backend SDK. -For example, using the JavaScript SDK: - -```js -const client = StreamChat.getInstance(‘api_key’, ‘api_secret’); -const notification_template = ` -{ - "title": "{{ sender.name }} @ {{ channel.name }}", - "body": "{{ message.text }}", - "click_action": "OPEN_ACTIVITY_1", - "sound": "default" -}`; - -client.updateAppSettings({ - firebase_config: { - notification_template, - }); -``` - -### Possible Issues - -Make sure to read the [general push notification docs](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart) in order to avoid known gotchas that may make your relationship with notifications difficult 😢. - -### Testing if Push Notifications are Setup Correctly - -If you're not sure whether you've set up push notifications correctly, for example, you don't always receive them, or they don’t work reliably, then you can follow these steps to make sure your configuration is correct and working: -1. Clone our repository for push testing: `git clone git@github.com:GetStream/chat-push-test.git` -2. `cd flutter` -3. In that folder run `flutter pub get` -4. Input your API key and secret in `lib/main.dart` -5. Change the bundle identifier/application ID and development team/user so you can run the app on your physical device.**Do not** run on an iOS simulator, as it will not work. Testing on an Android emulator is fine. -6. Add your `google-services.json/GoogleService-Info.plist` -7. Run the app -8. Accept push notification permission (iOS only) -9. Tap on `Device ID` and copy it -11. After configuring [stream-cli](https://github.com/GetStream/stream-cli), run the following command using your user ID: -```shell -stream chat:push:test -u -``` - -You should get a test push notification 🥳 - - -### Foreground Notifications - -Sometimes you may want to show a notification when the app is in the foreground. -For example, when you're in a channel and you receive a new message from someone in another channel. - -For this scenario, you can also use the `flutter_local_notifications` package to show a notification. - -You need to listen for new events using `FirebaseMessaging.onMessage.listen()` and handle them accordingly: - -```dart -FirebaseMessaging.onMessage.listen((message) async { - handleNotification( - message, - chatClient, - ); -}); -``` - -:::note -You should also check that the channel of the message is different than the channel in the foreground. -How you do this depends on your app infrastructure and how you handle navigation. -Take a look at the [Stream Chat v1 sample app](https://github.com/GetStream/flutter-samples/blob/main/packages/stream_chat_v1/lib/home_page.dart#L11) to see how we're doing it over there. -::: - -### Saving Notification Messages to the Offline Storage (Only Android) - -When the app is closed you may want to save received messages when you receive them via a notification so that later on when you open the app they're already there. - -To do this you need to integrate the package [`stream_chat_persistence`](https://pub.dev/packages/stream_chat_persistence) in our app that exports a persistence client, see [here](https://pub.dev/packages/stream_chat_persistence#usage) how to set it up. - -Then calling `FirebaseMessaging.onBackgroundMessage(...)` you need to use a TOP-LEVEL or STATIC function to handle background messages; here is an example: - -```dart -Future onBackgroundMessage(RemoteMessage message) async { - final chatClient = StreamChatClient(apiKey); - final persistenceClient = StreamChatPersistenceClient(); - - await persistenceClient.connect(userId); - - chatClient.connectUser( - User(id: userId), - userToken, - connectWebSocket: false, - ); - - handleNotification(message, chatClient); -} - -void handleNotification( - RemoteMessage message, - StreamChatClient chatClient, -) async { - final data = message.data; - if (data['type'] == 'message.new') { - final flutterLocalNotificationsPlugin = await setupLocalNotifications(); - final messageId = data['id']; - final cid = data['cid']; - final response = await chatClient.getMessage(messageId); - await persistenceClient.updateMessages(cid, [response.message]); - - persistenceClient.disconnect(); - - flutterLocalNotificationsPlugin.show( - 1, - 'New message from ${response.message.user.name} in ${response.channel.name}', - response.message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'new_message', - 'New message notifications channel', - )), - ); - } -} - -FirebaseMessaging.onBackgroundMessage(onBackgroundMessage); -``` - diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/autocomplete_triggers.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/autocomplete_triggers.mdx deleted file mode 100644 index b2c94be51c..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/autocomplete_triggers.mdx +++ /dev/null @@ -1,118 +0,0 @@ ---- -id: autocomplete_triggers -title: Adding Custom Autocomplete Triggers ---- - -Adding Custom Autocomplete Triggers - -### Introduction - -The [StreamMessageInput](../stream_chat_flutter/stream_message_input.mdx) widget provides a way to add custom autocomplete triggers using the `StreamMessageInput.customAutocompleteTriggers` property. - -By default we provide autocomplete triggers for mentions and commands, but it's very easy to add your custom ones. - -### Add Emoji Autocomplete Trigger - -To add a custom emoji autocomplete trigger, you must first create an `AutoCompleteOptions` widget. -This widget will be used to show the autocomplete options. - -For this example we're using two external dependencies: - -- [emojis](https://pub.dev/packages/emojis) -- [`substring_highlight`](https://pub.dev/packages/substring_highlight) - -```dart -import 'package:emojis/emoji.dart'; -import 'package:flutter/material.dart'; - -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:substring_highlight/substring_highlight.dart'; - -/// Overlay for displaying emoji that can be used -class StreamEmojiAutocompleteOptions extends StatelessWidget { - /// Constructor for creating a [StreamEmojiAutocompleteOptions] - const StreamEmojiAutocompleteOptions({ - super.key, - required this.query, - this.onEmojiSelected, - }); - - /// Query for searching emoji. - final String query; - - /// Callback called when an emoji is selected. - final ValueSetter? onEmojiSelected; - - @override - Widget build(BuildContext context) { - final emojis = Emoji.all().where((it) { - final normalizedQuery = query.toUpperCase(); - final normalizedShortName = it.shortName.toUpperCase(); - - return normalizedShortName.contains(normalizedQuery); - }); - - if (emojis.isEmpty) return const SizedBox.shrink(); - - return StreamAutocompleteOptions( - options: emojis, - optionBuilder: (context, emoji) { - final themeData = Theme.of(context); - return ListTile( - dense: true, - horizontalTitleGap: 0, - leading: Text( - emoji.char, - style: themeData.textTheme.headline6!.copyWith( - fontSize: 24, - ), - ), - title: SubstringHighlight( - text: emoji.shortName, - term: query, - textStyleHighlight: themeData.textTheme.headline6!.copyWith( - color: Colors.yellow, - fontSize: 14.5, - fontWeight: FontWeight.bold, - ), - textStyle: themeData.textTheme.headline6!.copyWith( - fontSize: 14.5, - ), - ), - onTap: onEmojiSelected == null ? null : () => onEmojiSelected!(emoji), - ); - }, - ); - } -} -``` - -Now it's time to use the `StreamEmojiAutocompleteOptions` widget. - -```dart -StreamMessageInput( - customAutocompleteTriggers: [ - StreamAutocompleteTrigger( - trigger: ':', - minimumRequiredCharacters: 2, - optionsViewBuilder: ( - context, - autocompleteQuery, - messageEditingController, - ) { - final query = autocompleteQuery.query; - return StreamEmojiAutocompleteOptions( - query: query, - onEmojiSelected: (emoji) { - // accepting the autocomplete option. - StreamAutocomplete.of(context).acceptAutocompleteOption( - emoji.char, - keepTrigger: false, - ); - }, - ); - }, - ), - ], -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/customize_message_actions.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/customize_message_actions.mdx deleted file mode 100644 index afb749f777..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/customize_message_actions.mdx +++ /dev/null @@ -1,81 +0,0 @@ ---- -id: customize_message_actions -title: Customize Message Actions ---- - -Customizing Message Actions - -### Introduction - -Message actions pop up in message overlay, when you long-press a message. - -![](../assets/message_actions.jpg) - -We have provided granular control over these actions. - -By default we render the following message actions: - -* edit message - -* delete message - -* reply - -* thread reply - -* copy message - -* flag message - -* pin message - -:::note -Edit and delete message are only available on messages sent by the user. -Additionally, pinning a message requires you to add the roles which are allowed to pin messages. -::: - -### Partially remove some message actions - -For example, if you only want to keep `"copy message"` and `"delete message"` -here is how to do it using the `messageBuilder` with our `StreamMessageWidget`. - -```dart -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - showFlagButton: false, - showEditMessage: false, - showCopyMessage: true, - showDeleteMessage: details.isMyMessage, - showReplyMessage: false, - showThreadReplyMessage: false, - ); - }, -) -``` - -### Add a new custom message action - -The SDK also allows you to add new actions into the dialog. - -For example, let's suppose you want to introduce a new message action - "Demo Action": - -We use the `customActions` parameter of the `StreamMessageWidget` to add extra actions. - -```dart -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - customActions: [ - StreamMessageAction( - leading: Icon(Icons.add), - title: Text('Demo Action'), - onTap: (message) { - /// Complete action here - }, - ), - ], - ); - }, -) -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/customize_message_widget.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/customize_message_widget.mdx deleted file mode 100644 index c27b9d3834..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/customize_message_widget.mdx +++ /dev/null @@ -1,181 +0,0 @@ ---- -id: customize_message_widget -title: Customizing The StreamMessageWidget ---- - -Customizing Text Messages - -### Introduction - -Every application provides a unique look and feel to their own messaging interface including and not -limited to fonts, colors, and shapes. - -This guide details how to customize the `StreamMessageWidget` in the Stream Chat Flutter UI SDK. - -### Building Custom Messages - -This guide goes into detail about the ability to customize the `StreamMessageWidget`. However, if you want -to customize the default `StreamMessageWidget` in the `StreamMessageListView` provided, you can use the `.copyWith()` method -provided inside the `messageBuilder` parameter of the `StreamMessageListView` like this: - -```dart -StreamMessageListView( - messageBuilder: (context, details, messageList, defaultImpl) { - // Your implementation of the message here - // E.g: return Text(details.message.text ?? ''); - }, -), -``` - -### Theming - -You can customize the `StreamMessageWidget` using the `StreamChatTheme` class, so that you can change the -message theme at the top instead of creating your own `StreamMessageWidget` at the lower implementation level. - -There are several things you can change in the theme including text styles and colors of various elements. - -You can also set a different theme for the user's own messages and messages received by them. - -:::note -Theming allows you to change minor factors like style while using the widget directly allows you much -more customization such as replacing a certain widget with another. Some things can only be customized -through the widget and not the theme. -::: - -Here is an example: - -```dart -StreamChatThemeData( - - /// Sets theme for user's messages - ownMessageTheme: StreamMessageThemeData( - messageBackgroundColor: colorTheme.textHighEmphasis, - ), - - /// Sets theme for received messages - otherMessageTheme: StreamMessageThemeData( - avatarTheme: StreamAvatarThemeData( - borderRadius: BorderRadius.circular(8), - ), - ), - -) -``` - -![](../assets/message_theming.png) - -#### Change message text style - -The `StreamMessageWidget` has multiple `Text` widgets that you can manipulate the styles of. The three main -are the actual message text, user name, message links, and the message timestamp. - -```dart -StreamMessageThemeData( - messageTextStyle: TextStyle(...), - createdAtStyle: TextStyle(...), - messageAuthorStyle: TextStyle(...), - messageLinksStyle: TextStyle(...), -) -``` - -![](../assets/message_styles.png) - -#### Change avatar theme - -You can change the attributes of the avatar (if displayed) using the `avatarTheme` property. - -```dart -StreamMessageThemeData( - avatarTheme: StreamAvatarThemeData( - borderRadius: BorderRadius.circular(8), - ), -) -``` - -![](../assets/message_rounded_avatar.png) - -#### Changing Reaction theme - -You also customize the reactions attached to every message using the theme. - -```dart -StreamMessageThemeData( - reactionsBackgroundColor: Colors.red, - reactionsBorderColor: Colors.redAccent, - reactionsMaskColor: Colors.pink, -), -``` - -![](../assets/message_reaction_theming.png) - -### Changing Message Actions - -When a message is long pressed, the `StreamMessageActionsModal` is shown. - -The `StreamMessageWidget` allows showing or hiding some options if you so choose. - -```dart -StreamMessageWidget( - ... - showUsername = true, - showTimestamp = true, - showReactions = true, - showDeleteMessage = true, - showEditMessage = true, - showReplyMessage = true, - showThreadReplyMessage = true, - showResendMessage = true, - showCopyMessage = true, - showFlagButton = true, - showPinButton = true, - showPinHighlight = true, -), -``` - -![](../assets/message_widget_actions.png) - -### Building attachments - -The `customAttachmentBuilders` property allows you to build any kind of attachment (inbuilt or custom) -in your own way. While a separate guide is written for this, it is included here because of relevance. - -```dart -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - customAttachmentBuilders: { - 'location': (context, message, attachments) { - final attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'], - attachments[0].extraData['longitude'], - ), - ); - - return wrapAttachmentWidget(context, attachmentWidget, null, true, BorderRadius.circular(8.0)); - } - }, - ); - }, -), -``` - -### Widget Builders - -Some parameters allow you to construct your own widget in place of some elements in the `StreamMessageWidget`. - -These are: -* `userAvatarBuilder` : Allows user to substitute their own widget in place of the user avatar. -* `editMessageInputBuilder` : Allows user to substitute their own widget in place of the input in edit mode. -* `textBuilder` : Allows user to substitute their own widget in place of the text. -* `bottomRowBuilder` : Allows user to substitute their own widget in the bottom of the message when not deleted. -* `deletedBottomRowBuilder` : Allows user to substitute their own widget in the bottom of the message when deleted. - -```dart -StreamMessageWidget( - ... - textBuilder: (context, message) { - // Add your own text implementation here. - }, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/customize_text_messages.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/customize_text_messages.mdx deleted file mode 100644 index 1634173462..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/customize_text_messages.mdx +++ /dev/null @@ -1,157 +0,0 @@ ---- -id: customize_text_messages -title: Customize Text Messages ---- - -Customizing Text Messages - -### Introduction - -Every application provides a unique look and feel to their own messaging interface including and not -limited to fonts, colors, and shapes. - -This guide details how to customize message text in the `StreamMessageListView` / `StreamMessageWidget` in the -Stream Chat Flutter UI SDK. - -:::note -This guide is specifically for the `StreamMessageListView` but if you intend to display a `StreamMessageWidget` -separately, follow the same process without the `.copyWith` and use the default constructor instead. -::: - -### Basics of customizing a `StreamMessageWidget` - -First, add a `StreamMessageListView` in the appropriate place where you intend to display messages from a -channel. - -```dart -StreamMessageListView( - ... -) -``` - -Now, we use the `messageBuilder` parameter to build a custom message. The builder function also provides -the default implementation of the `StreamMessageWidget` so that we can change certain aspects of the widget -without redoing all of the default parameters. - -:::note -In earlier versions of the SDK, some `StreamMessageWidget` parameters were exposed directly through the `StreamMessageListView`, -however, this quickly becomes hard to maintain as more parameters and customizations are added to the -`StreamMessageWidget`. Newer version utilise a cleaner interface to change the parameters by supplying a -default message implementation as aforementioned. -::: - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget; - }, -) -``` - -We use `.copyWith()` to customize the widget: - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - ... - ); - }, -) -``` - -### Customizing text - -If you intend to simply change the theme for the text, you need not recreate the whole widget. The -`StreamMessageWidget` has a `messageTheme` parameter that allows you to pass the theme for most aspects -of the message. - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - messageTheme: StreamMessageThemeData( - ... - messageTextStyle: TextStyle(), - ), - ); - }, -) -``` - -If you want to replace the entire text widget in the `StreamMessageWidget`, you can use the `textBuilder` -parameter which provides a builder for creating a widget to substitute the default text.parameter - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - textBuilder: (context, message) { - return Text(message.text); - }, - ); - }, -) -``` - -### Adding Hashtags - -To add elements like hashtags, we can override the `textBuilder` in the StreamMessageWidget: - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - textBuilder: (context, message) { - final text = _replaceHashtags(message.text).replaceAll('\n', '\\\n'); - final messageTheme = StreamChatTheme.of(context).ownMessageTheme; - - return MarkdownBody( - data: text, - onTapLink: ( - String link, - String href, - String title, - ) { - // Do something with tapped hashtag - }, - styleSheet: MarkdownStyleSheet.fromTheme( - Theme.of(context).copyWith( - textTheme: Theme.of(context).textTheme.apply( - bodyColor: messageTheme.messageText.color, - decoration: messageTheme.messageText.decoration, - decorationColor: messageTheme.messageText.decorationColor, - decorationStyle: messageTheme.messageText.decorationStyle, - fontFamily: messageTheme.messageText.fontFamily, - ), - ), - ).copyWith( - a: messageTheme.messageLinks, - p: messageTheme.messageText, - ), - ); - }, - ); - }, -) - -String _replaceHashtags(String text) { - RegExp exp = new RegExp(r"\B#\w\w+"); - exp.allMatches(text).forEach((match){ - text = text.replaceAll( - '${match.group(0)}', '[${match.group(0)}](${match.group(0).replaceAll(' ', '')})'); - }); - return text; -} -``` - -We can replace the hashtags using RegEx and add links for the MarkdownBody which is done here in the -`_replaceHashtags()` function. -Inside the textBuilder, we use the `flutter_markdown` package to build our hashtags as links. - -![](../assets/hashtag_example.jpg) diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/end_to_end_chat_encryption.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/end_to_end_chat_encryption.mdx deleted file mode 100644 index fabf5f6e4c..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/end_to_end_chat_encryption.mdx +++ /dev/null @@ -1,257 +0,0 @@ ---- -id: end_to_end_chat_encryption -title: End To End Chat Encryption ---- - -## Introduction - -When you communicate over a chat application with another person or group, -you may exchange sensitive information, like personally identifiable information, financial details, or passwords. -A chat application should use end-to-end encryption to ensure that users' data stays secure. - -:::note -Before you start, keep in mind that this guide is a basic example intended for educational purposes only. -If you want to implement end-to-end encryption in your production app, please consult a security professional first. -There’s a lot more to consider from a security perspective that isn’t covered here. -::: - -## What is End-to-End Encryption? - -End-to-end encryption (E2EE) is the process of securing a message from third parties so that only the sender and receiver can access the message. -E2EE provides security by storing the message in an encrypted form on the application's server or database. - -You can only access the message by decrypting and signing it using a known public key (distributed freely) -and a corresponding private key (only known by the owner). - -Each user in the application has their own public-private key pair. -Public keys are distributed publicly and encrypt the sender’s messages. -The receiver can only decrypt the sender’s message with the matching private key. - -Check out the diagram below for an example: - -![](../assets/end_to_end_encryption.png) - -## Setup - -### Dependencies - -Add the [web cryptographic](https://pub.dev/packages/webcrypto) package in your `pubspec.yaml` file. - -```yaml -dependencies: - webcrypto: ^0.5.2 # latest version -``` - -### Generate Key Pair - -Write a function that generates a key pair using the **ECDH** algorithm and the **P-256** elliptic curve (**P-256** is well-supported and -offers the right balance of security and performance). - -The pair will consist of two keys: -- **PublicKey**: The key that is linked to a user to encrypt messages. -- **PrivateKey**: The key that is stored locally to decrypt messages. - -```dart -Future generateKeys() async { - final keyPair = await EcdhPrivateKey.generateKey(EllipticCurve.p256); - final publicKeyJwk = await keyPair.publicKey.exportJsonWebKey(); - final privateKeyJwk = await keyPair.privateKey.exportJsonWebKey(); - - return JsonWebKeyPair( - privateKey: json.encode(privateKeyJwk), - publicKey: json.encode(publicKeyJwk), - ); -} - -// Model class for storing keys -class JsonWebKeyPair { - const JsonWebKeyPair({ - required this.privateKey, - required this.publicKey, - }); - - final String privateKey; - final String publicKey; -} -``` - -### Generate a Cryptographic Key - -Next, create a symmetric **Cryptographic Key** using the keys generated in the previous step. -You will use those keys to encrypt and decrypt messages. - -```dart -// SendersJwk -> sender.privateKey -// ReceiverJwk -> receiver.publicKey -Future> deriveKey(String senderJwk, String receiverJwk) async { - // Sender's key - final senderPrivateKey = json.decode(senderJwk); - final senderEcdhKey = await EcdhPrivateKey.importJsonWebKey( - senderPrivateKey, - EllipticCurve.p256, - ); - - // Receiver's key - final receiverPublicKey = json.decode(receiverJwk); - final receiverEcdhKey = await EcdhPublicKey.importJsonWebKey( - receiverPublicKey, - EllipticCurve.p256, - ); - - // Generating CryptoKey - final derivedBits = await senderEcdhKey.deriveBits(256, receiverEcdhKey); - return derivedBits; -} -``` - -### Encrypting Messages - -Once you have generated the **Cryptographic Key**, you're ready to encrypt the message. -You can use the **AES-GCM** algorithm for its known security and performance balance and good browser availability. - -```dart -// The "iv" stands for initialization vector (IV). To ensure the encryption’s strength, -// each encryption process must use a random and distinct IV. -// It’s included in the message so that the decryption procedure can use it. -final Uint8List iv = Uint8List.fromList('Initialization Vector'.codeUnits); -``` - -```dart -Future encryptMessage(String message, List deriveKey) async { - // Importing cryptoKey - final aesGcmSecretKey = await AesGcmSecretKey.importRawKey(deriveKey); - - // Converting message into bytes - final messageBytes = Uint8List.fromList(message.codeUnits); - - // Encrypting the message - final encryptedMessageBytes = - await aesGcmSecretKey.encryptBytes(messageBytes, iv); - - // Converting encrypted message into String - final encryptedMessage = String.fromCharCodes(encryptedMessageBytes); - return encryptedMessage; -} -``` - -### Decrypting Messages - -Decrypting a message is the opposite of encrypting one. -To decrypt a message to a human-readable format, use the code snippet below: - -```dart -Future decryptMessage(String encryptedMessage, List deriveKey) async { - // Importing cryptoKey - final aesGcmSecretKey = await AesGcmSecretKey.importRawKey(deriveKey); - - // Converting message into bytes - final messageBytes = Uint8List.fromList(encryptedMessage.codeUnits); - - // Decrypting the message - final decryptedMessageBytes = - await aesGcmSecretKey.decryptBytes(messageBytes, iv); - - // Converting decrypted message into String - final decryptedMessage = String.fromCharCodes(decryptedMessageBytes); - return decryptedMessage; -} -``` - -## Implement as a Stream Chat Feature - -Now that your setup is complete you can use it to implement end-to-end encryption in your app. - -### Store User's Public Key - -The first thing you need to do is store the generated `publicKey` as an `extraData` property, in order -for other users to encrypt messages. - -```dart -// Generating keyPair using the function defined in above steps -final keyPair = generateKeys(); -``` - -```dart -await client.connectUser( - User( - id: 'cool-shadow-7', - name: 'Cool Shadow', - image: 'https://getstream.io/cool-shadow', - - // set publicKey as a extraData property - extraData: { 'publicKey': keyPair.publicKey }, - ), - client.devToken('cool-shadow-7').rawValue, -); -``` - -### Sending Encrypted Messages - -Now you will use the `encryptMessage()` function created in the previous steps to encrypt the message. - -To do that, you need to make some minor changes to the **StreamMessageInput** widget. - -```dart -final receiverJwk = receiver.extraData['publicKey']; - -// Generating derivedKey using user's privateKey and receiver's publicKey -final derivedKey = await deriveKey(keyPair.privateKey, receiverJwk); -``` - -```dart -StreamMessageInput( - - ... - - preMessageSending: (message) async { - // Encrypting the message text using derivedKey - final encryptedMessage = await encryptMessage(message.text, derivedKey); - - // Creating a new message with the encrypted message text - final newMessage = message.copyWith(text: encryptedMessage); - - return newMessage; - }, -), -``` - -`preMessageSending` is a parameter that allows your app to process the message before it goes to Stream’s server. -Here, you have used it to encrypt the message before sending it to Stream’s backend. - -### Showing Decrypted Messages - -Now, it’s time to decrypt the message and present it in a human-readable format to the receiver. - -You can customize the **StreamMessageListView** widget to have a custom `messagebuilder`, that can decrypt the message. - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, currentMessages, defaultWidget) { - // Retrieving the message from details - final message = messageDetails.message; - - // Decrypting the message text using the derivedKey - final decryptedMessageFuture = decryptMessage(message.text, derivedKey); - return FutureBuilder( - future: decryptedMessageFuture, - builder: (context, snapshot) { - if (snapshot.hasError) return Text('Error: ${snapshot.error}'); - if (!snapshot.hasData) return Container(); - - // Updating the original message with the decrypted text - final decryptedMessage = message.copyWith(text: snapshot.data); - - // Returning defaultWidget with updated message - return defaultWidget.copyWith( - message: decryptedMessage, - ); - }, - ); - }, -), -``` - -That's it. That's all you need to implement E2EE in a Stream powered chat app. - -For more details, check out our [end-to-end encrypted chat article](https://getstream.io/blog/end-to-end-encrypted-chat-in-flutter/#whats-end-to-end-encryption). diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/error_reporting_with_sentry.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/error_reporting_with_sentry.mdx deleted file mode 100644 index 5aa1870347..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/error_reporting_with_sentry.mdx +++ /dev/null @@ -1,143 +0,0 @@ ---- -id: error_reporting_with_sentry -title: Error Reporting With Sentry ---- - -Error Reporting With Sentry - -## Introduction - -While one always tries to create apps that are free of bugs, they're sure to crop up from time to time. Since buggy apps lead to unhappy users and customers, it's important to understand how often your users experience bugs and where those bugs occur. That way, you can prioritize the bugs with the highest impact and work to fix them. - -Whenever an error occurs, create a report containing the error that occurred and the associated stack trace. You can then send the report to an error tracking service, such as [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), or [Firebase Crashlytics](https://firebase.google.com/docs/crashlytics). - -The error tracking service aggregates all of the crashes your users experience and groups them together. This allows you to know how often your app fails and where your users run into trouble. - -In this guide, learn how to report Stream Chat errors to the [Sentry](https://sentry.io/welcome/) crash reporting service using the following steps. - -### 1. Get a DSN From Sentry - -Before reporting errors to Sentry, you need a “DSN” to uniquely identify your app with the Sentry service: -To get a DSN, use the following steps: - -- [Create an account with Sentry](https://sentry.io/signup/). -- Log in to the account. -- Create a new Flutter project. -- Copy the code snippet that includes the DSN. - -### 2. Import the Sentry package - -Import the `sentry_flutter` package into your app. The sentry package makes it easier to send error reports to the Sentry error tracking service. - -```yaml -dependencies: - sentry_flutter: -``` - -### 3. Initialize the Sentry SDK - -Initialize the SDK to capture different unhandled errors automatically. - -```dart -import 'package:sentry_flutter/sentry_flutter.dart'; - -Future main() async { - await SentryFlutter.init( - (options) => options.dsn = 'https://example@sentry.io/example', - appRunner: () => runApp(const MyApp()), - ); -} -``` - -Or, if you want to run your app in your own error zone, use `runZonedGuarded`: - -```dart -void main() async { - /// Captures errors reported by the Flutter framework. - FlutterError.onError = (FlutterErrorDetails details) { - if (kDebugMode) { - // In development mode, simply print to console. - FlutterError.dumpErrorToConsole(details); - } else { - // In production mode, report to the application zone to report to Sentry. - Zone.current.handleUncaughtError(details.exception, details.stack!); - } - }; - - Future _reportError(dynamic error, StackTrace stackTrace) async { - // Print the exception to the console. - if (kDebugMode) { - // Print the full stack trace in debug mode. - print(stackTrace); - return; - } else { - // Send the Exception and Stacktrace to sentry in Production mode. - await Sentry.captureException(error, stackTrace: stackTrace); - } - } - - runZonedGuarded( - () async { - await SentryFlutter.init( - (options) => options.dsn = 'https://example@sentry.io/example', - ); - runApp(const MyApp()); - }, - _reportError, - ); -} -``` - -Alternatively, you can pass the DSN to Flutter using the **dart-define** tag: - -```bash ---dart-define SENTRY_DSN=https://example@sentry.io/example -``` - -### 4. Integration With StreamChat Applications - -Override the default `logHandlerFunction` to send errors to Sentry. - -```dart -void sampleAppLogHandler(LogRecord record) async { - if (kDebugMode) StreamChatClient.defaultLogHandler(record); - - // Report errors to Sentry - if (record.error != null || record.stackTrace != null) { - await Sentry.captureException( - record.error, - stackTrace: record.stackTrace, - ); - } -} - -StreamChatClient buildStreamChatClient( - String apiKey, { - Level logLevel = Level.SEVERE, -}) { - return StreamChatClient( - apiKey, - logLevel: logLevel, - logHandlerFunction: sampleAppLogHandler, // Pass the overridden logHandlerFunction - ); -} -``` - -### 5. Capture Errors Programmatically - -Besides the automatic error reporting that Sentry generates by importing and initializing the SDK, -you can use the API to manually report errors to Sentry: - -```dart -await Sentry.captureException(exception, stackTrace: stackTrace); -``` - -For more information, see the [Sentry API](https://pub.dev/documentation/sentry_flutter/latest/sentry_flutter/sentry_flutter-library.html) docs on Pub. - -### Complete Example - -To view a working example, see the [Stream Sample app](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). - -### Learn More - -Extensive documentation about using the Sentry SDK can be found on [Sentry's site](https://docs.sentry.io/platforms/flutter/). diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/migration_guide_4_0.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/migration_guide_4_0.mdx deleted file mode 100644 index 6842e704e8..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/migration_guide_4_0.mdx +++ /dev/null @@ -1,752 +0,0 @@ ---- -id: migration_guide_4_0 -title: Migration Guide v4.0 ---- - -**Version 4.0.0** of the Stream Chat Flutter SDK carries significant architectural changes to improve the developer experience by giving you more control and flexibility in how you use our core components and UI widgets. - -This guide is intended to enumerate and better explain the changes in the SDK. - -If you find any bugs or have any questions, please file an [issue on our GitHub repository](https://github.com/GetStream/stream-chat-flutter/issues). We want to support you as much as we can with this migration. - -Code examples: - -- See our [Stream Chat Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) for an up-to-date guide using the latest Stream Chat version. -- See the [Stream Flutter Samples repository](https://github.com/GetStream/flutter-samples) with our full fledged messaging [sample application](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). - -All of our documentation has also been updated to support v4, so all of the guides and examples will have updated code. - -### Dependencies - -To migrate to v4.0.0, update your `pubspec.yaml` with the correct Stream chat package you're using: - -```yaml -dependencies: - stream_chat_flutter: ^4.0.0 # full UI, core and client packages - stream_chat_flutter_core: ^4.0.0 # core and client packages - stream_chat: ^4.0.0 # client package -``` - ---- - -## Name Changes - -The majority of the Stream Chat widgets and classes have now been renamed to have a “Stream” prefix associated with them. This increases Stream widgets' discoverability and avoids name conflicts when importing. - -For example, `MessageListView` is now called `StreamMessageListView`, and `UserAvatar` is renamed to `StreamUserAvatar`. - -**The old class names are deprecated and will be removed in the next major release (v5.0.0).** - -See the sections below on “deprecated classes” for a complete list of changes. Some of these classes/widgets have undergone functional changes as well, that will be explore in the following sections. - -## Removed Functionality/Widgets - -This section highlights functionality removed. - -### Removed Methods And Classes - -In version 4 we removed the following deprecated methods and classes: - -* `Channel.banUser` - -* `Channel.unbanUser` - -* `ClientState.user` - -* `ClientState.userStream` - -* `MessageWidget.allRead` - -* `MessageWidget.readList` - -* `StreamChat.user` - -* `StreamChat.userStream` - -* `StreamChatCore.user` - -* `StreamChatCore.userStream` - -These were marked as deprecated in v3. - -### Video Compression - -The automatic video compression when uploading a video has been removed. You can integrate this yourself by manipulating attachments using a [custom attachment uploader](https://getstream.io/chat/docs/flutter-dart/file_uploads/?language=dart). - -### Slidable Channel List Item - -The default slidable channel preview behavior has been removed. We have created a [guide](slidable_channel_list_preview.mdx) showing you how you can easily add this functionality yourself. - -![Slidable demo](../assets/slidable_demo.jpg) - -### Pin Permission - -`pinPermissions` is no longer needed in the **MessageListView** widget. The permissions are automatically fetched for each Stream project. To enable users to pin the message, make sure the pin permissions are granted for different types of users on your [Stream application dashboard](https://dashboard.getstream.io/). - ---- - -## Deprecated Classes - -This section covers all the deprecated classes and widgets in the Stream chat packages. Some of these have also undergone functional changes, for example, **MessageInput** and **ChannelsBloc**. These are discussed in more detail below. - -The majority of the Stream widgets and classes have now been renamed to have a **"Stream"** prefix associated with them. - -Changes: - -- `AttachmentTitle` in favor of `StreamAttachmentTitle` -- `AttachmentUploadStateBuilder` in favor of `StreamAttachmentsUploadStateBuilder` -- `AttachmentWidget` in favor of `StreamAttachmentWidget` -- `AvatarThemeData` in favor of `StreamAvatarThemeData` -- `ChannelAvatar` in favor of `StreamChannelAvatar` -- `ChannelBottomSheet` in favor of `StreamChannelInfoBottomSheet` -- `ChannelHeader` in favor of `StreamChannelHeader` -- `ChannelHeaderTheme` in favor of `StreamChannelHeaderTheme` -- `ChannelHeaderThemeData` in favor of `StreamChannelHeaderThemeData` -- `ChannelInfo` in favor of `StreamChannelInfo` -- `ChannelListHeader` in favor of `StreamChannelListHeader` -- `ChannelListHeaderTheme` in favor of `StreamChannelListHeaderTheme` -- `ChannelListHeaderThemeData` in favor of `StreamChannelListHeaderThemeData` -- `ChannelListView` in favor of `StreamChannelListView` -- `ChannelListViewTheme` in favor of `StreamChannelListViewTheme` -- `ChannelListViewThemeData` in favor of `StreamChannelListViewThemeData` -- `ChannelListHeader` in favor of `StreamChannelListHeader` -- `ChannelListView` in favor of `StreamChannelListView` -- `ChannelName` in favor of `StreamChannelName` -- `ChannelPreview` in favor of `StreamChannelListTile` -- `ChannelPreviewTheme` in favor of `StreamChannelPreviewTheme` -- `ChannelPreviewThemeData` in favor of `StreamChannelPreviewThemeData` -- `ChannelName` in favor of `StreamChannelName` -- `ColorTheme` in favor of `StreamColorTheme` -- `CommandsOverlay` in favor of `StreamCommandsOverlay` -- `ConnectionStatusBuilder` in favor of `StreamConnectionStatusBuilder` -- `DateDivider` in favor of `StreamDateDivider` -- `DeletedMessage` in favor of `StreamDeletedMessage` -- `EmojiOverlay` in favor of `StreamEmojiOverlay` -- `FileAttachment` in favor of `StreamFileAttachment` -- `FullScreenMedia` in favor of `StreamFullScreenMedia` -- `GalleryFooter` in favor of `StreamGalleryFooter` -- `GalleryFooterThemeData` in favor of `StreamGalleryFooterThemeData` -- `GalleryHeader` in favor of `StreamGalleryHeader` -- `GalleryHeaderTheme` in favor of `StreamGalleryHeaderTheme` -- `GalleryHeaderThemeData` in favor of `StreamGalleryHeaderThemeData` -- `GiphyAttachment` in favor of `StreamGiphyAttachment` -- `GradientAvatar` in favor of `StreamGradientAvatar` -- `GroupAvatar` in favor of `StreamGroupAvatar` -- `ImageAttachment` in favor of `StreamImageAttachment` -- `ImageGroup` in favor of `StreamImageGroup` -- `InfoTile` in favor of `StreamInfoTile` -- `MediaListView` in favor of `StreamMediaListView` -- `MessageAction` in favor of `StreamMessageAction` -- `MessageActionsModal` in favor `StreamMessageActionsModal` -- `MessageInput` in favor of `StreamMessageInput` -- `MessageInputTheme` in favor of `StreamMessageInputTheme` -- `MessageInputThemeData` in favor of `StreamMessageInputThemeData` -- `MessageInputState` in favor of `StreamMessageInput` -- `MessageListView` in favor of `StreamMessageListView` -- `MessageListViewTheme` in favor of `StreamMessageListViewTheme` -- `MessageListViewThemeData` in favor of `StreamMessageListViewThemeData` -- `MessageSearchListView` in favor of `StreamMessageSearchListView` -- `MessageSearchListViewTheme` in favor of `StreamMessageSearchListViewTheme` -- `MessageSearchListViewThemeData` in favor of `StreamMessageSearchListViewThemeData` -- `MessageReactionsModal` in favor of `StreamMessageReactionsModal` -- `MessageSearchItem` in favor of `StreamMessageSearchItem` -- `MessageSearchListView` in favor of `StreamMessageSearchListView` -- `MessageText` in favor of `StreamMessageText` -- `MessageWidget` in favor of `StreamMessageWidget` -- `MessageThemeData` in favor of `StreamMessageThemeData` -- `MultiOverlay` in favor of `StreamMultiOverlay` -- `OptionListTile` in favor of `StreamOptionListTile` -- `QuotedMessageWidget` in favor of `StreamQuotedMessageWidget` -- `ReactionBubble` in favor of `StreamReactionBubble` -- `ReactionIcon` in favor of `StreamReactionIcon` -- `ReactionPicker` in favor of `StreamReactionPicker` -- `SendingIndicator` in favor of `StreamSendingIndicator` -- `SystemMessage` in favor of `StreamSystemMessage` -- `TextTheme` in favor of `StreamTextTheme` -- `ThreadHeader` in favor of `StreamThreadHeader` -- `TypingIndicator` in favor of `StreamTypingIndicator` -- `UnreadIndicator` in favor of `SteamUnreadIndicator` -- `UploadProgressIndicator` in favor of `StreamUploadProgressIndicator` -- `UrlAttachment` in favor of `StreamUrlAttachment` -- `UserAvatar` in favor of `StreamUserAvatar` -- `UserItem` in favor of `StreamUserItem` -- `UserListView` in favor of `StreamUserListView` -- `UserListViewTheme` in favor of `StreamUserListViewTheme` -- `UserListViewThemeData` in favor of `StreamUserListViewThemeData` -- `UserMentionTile` in favor of `StreamUserMentionTile` -- `UserMentionsOverlay` in favor of `StreamUserMentionsOverlay` -- `VideoAttachment` in favor of `StreamVideoAttachment` -- `VideoService` in favor of `StreamVideoService` -- `VideoThumbnailImage` in favor of `StreamVideoThumbnailImage` -- `VisibleFootnote` in favor of `StreamVisibleFootnote` - -## ChannelListView to StreamChannelListView - -The `ChannelListView` widget has been deprecated, and it is now recommended to use `StreamChannelListView`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `StreamChannelListController`. This controller manages the content for a channel list; it lets you perform tasks such as: - -- Load initial data. -- Use channel events handlers. -- Load more data using `loadMore`. -- Replace the previously loaded channels. -- Return/Create a new channel and start watching it. -- Pause and Resume all subscriptions added to this composite. - -For more information see the [`StreamChannelListView` documentation](../stream_chat_flutter/stream_channel_list_view.mdx). - -### ChannelsBloc to StreamChannelListController - -The `ChannelsBloc` widget should be replaced with `StreamChannelListController`. This controller provides all the functionality needed to query and manipulate channel data previously accessible through `ChannelsBloc`. - -For more information see the [`StreamChannelListController` documentation](../stream_chat_flutter_core/stream_channel_list_controller.mdx). - -### StreamChannelListView Examples - -Let's explore some examples of the functional differences when using the new `StreamChannelListView`. - -The **StreamChannelListController** provides various methods, such as: - -- **`deleteChannel`** -- **`loadMore`** -- **`muteChannel`** -- **`deleteChannel`** - -For a complete list with additional information, see the code documentation. - -#### Basic Use - -The following code demonstrates the old way of creating a **ChannelListPage**, that displays a list of channels: - -```dart -class ChannelListPage extends StatelessWidget { - const ChannelListPage({ - Key? key, - }) : super(key: key); - - @override - // ignore: prefer_expression_function_bodies - Widget build(BuildContext context) { - return Scaffold( - body: ChannelsBloc( - child: ChannelListView( - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - sort: const [SortOption('last_message_at')], - limit: 20, - channelWidget: const ChannelPage(), - ), - ), - ); - } -} -``` - -In **v4** this can now be achieved with the following: - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -As you can see, the **ChannelsBloc** has been replaced with a **StreamChannelListController**, where the **filter**, **limit**, and **sort** arguments can be set. The above code also demonstrates how to refresh the channel list by calling `_controller.refresh()`. - -## MessageSearchListView to StreamMessageSearchListView - -The `MessageSearchListView` widget has been deprecated, and it is now recommended to use `StreamMessageSearchListView`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `StreamMessageSearchListController`. This controller manages the content when searching for a message; it lets you perform tasks such as: - -- Load initial data. -- Set filters and search terms. -- Load more data using `loadMore`. -- Refresh data. - -For more information see the [`StreamMessageSearchListView` documentation](../stream_chat_flutter/stream_message_search_list_view.mdx). - -### MessageSearchBloc to StreamMessageSearchListController - -The `MessageSearchBloc` widget should be replaced with a `StreamMessageSearchListController`. This controller provides all the functionality needed to query and manipulate message search data previously accessible through `MessageSearchBloc`. - -For more information see the [`StreamMessageSearchListController` documentation](../stream_chat_flutter_core/stream_message_search_list_controller.mdx). - -### StreamMessageSearchListView Example - -The following code demonstrates the old way of searching for messages: - -```dart -class SearchExample extends StatelessWidget { - const SearchExample({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return MessageSearchBloc( - child: MessageSearchListView( - showErrorTile: true, - messageQuery: 'message query', - filters: Filter.in_('members', const ['user-id']), - sortOptions: const [ - SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - pullToRefresh: false, - limit: 30, - emptyBuilder: (context) => const Text('Nothing to show'), - itemBuilder: (context, messageResponse) { - /// Return widget - } - onItemTap: (messageResponse) { - /// Handle on tap - } - ), - ); - } -} -``` - -In **v4**, this can now be achieved with the following: - -```dart -class SearchExample extends StatefulWidget { - const SearchExample({ - Key? key, - }) : super(key: key); - - @override - State createState() => _SearchExampleState(); -} - -class _SearchExampleState extends State { - late final StreamMessageSearchListController _messageSearchListController = - StreamMessageSearchListController( - client: StreamChat.of(context).client, - filter: Filter.in_('members', [StreamChat.of(context).currentUser!.id]), - limit: 5, - searchQuery: '', - sort: [ - const SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - ); - - search() { - _messageSearchListController.searchQuery = 'search-value'; - _messageSearchListController.doInitialLoad(); - } - - @override - dispose() { - _messageSearchListController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return StreamMessageSearchListView( - controller: _messageSearchListController, - emptyBuilder: (context) => const Text('Nothing to show'), - itemBuilder: ( - context, - messageResponses, - index, - defaultWidget, - ) { - return defaultWidget.copyWith(); // modify default widget - }); - } -} -``` - -## UserListView to StreamUserListView - -The `UserListView` widget has been deprecated, and it is now recommended to use `StreamUserListView`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `StreamUserListController`. This controller manages the content when retrieving Stream users; it let's you perform tasks, such as: - -- Load data. -- Set filters. -- Refresh data. - -For more information see the [`StreamUserListView` documentation](../stream_chat_flutter/stream_user_list_view.mdx). - -### UsersBloc to StreamUserListController - -The `UsersBloc` widget should be replaced with a `StreamUserListController`. This controller provides all the functionality needed to query and manipulate user data previously accessible through `UsersBloc`. - -For more information see the [`StreamUserListController` documentation](../stream_chat_flutter_core/stream_user_list_controller.mdx). - -### StreamUserListView Example - -The following code demonstrates the old way of displaying all users: - -```dart -class UsersExample extends StatelessWidget { - const UsersExample({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return UsersBloc( - child: UserListView( - groupAlphabetically: true, - onUserTap: (user, _) { - /// Handle on tap - }, - limit: 25, - filter: Filter.and([ - Filter.autoComplete('name', 'some-name'), - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]), - sort: const [ - SortOption( - 'name', - direction: 1, - ), - ], - ), - ); - } -} -``` - -In **v4**, this can now be achieved with the following: - -```dart -class UsersExample extends StatefulWidget { - const UsersExample({ - Key? key, - }) : super(key: key); - - @override - State createState() => _UsersExampleState(); -} - -class _UsersExampleState extends State { - late final userListController = StreamUserListController( - client: StreamChat.of(context).client, - limit: 25, - filter: Filter.and([ - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - void _load() { - userListController.filter = Filter.and([ - Filter.autoComplete('name', 'some-name'), - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]); - userListController.doInitialLoad(); - } - - @override - dispose() { - userListController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return StreamUserListView( - controller: userListController, - onUserTap: (user) { - /// Handle on tap - }, - emptyBuilder: (context) => const Text('Nothing to show'), - itemBuilder: ( - context, - users, - index, - defaultWidget, - ) { - return defaultWidget.copyWith(); // modify default widget - }, - ); - } -} -``` - -## MessageInput to StreamMessageInput - -The `MessageInput` widget has been deprecated, and it is now recommended to use `StreamMessageInput`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `MessageInputController`. This controller maintains the state of the message input and exposes various methods to allow you to customize and manipulate the underlying **Message** value. - -Creating a separate controller allows easier control over the message input content by moving logic out of the deprecated `MessageInput` and into the controller. This controller can then be created, managed, and exposed in whatever way you like. - -The widget is also separated into smaller components: `StreamCountDownButton`, `StreamAttachmentPicker`, etc. - -> ❗The `MessageInputController` is exposed by the **`stream_chat_flutter_core`** package. This allows you to use the controller even if you're not using the UI components. - -As a result of this extra control, it is no longer needed for the new `StreamMessageInput` widget to expose these `MessageInput` arguments: - -- `parentMessage`: parent message in case of a thread -- `editMessage`: message to edit -- `initialMessage`: message to start with -- `quotedMessage`: message to quote/reply -- `onQuotedMessageCleared`: callback for clearing quoted message -- `textEditingController`: the text controller of the text field - -The following arguments are newly introduced to the `StreamMessageInput`, and are not available on the old `MessageInput`: - -- `messageInputController`: the controller for the message input -- `attachmentsPickerBuilder`: builder for bottom sheet when attachment picker is opened -- `sendButtonBuilder`: builder for creating send button -- `validator`: a callback function that validates the message -- `restorationId`: restoration ID to save and restore the state of the MessageInput -- `enableSafeArea`: wraps the **StreamMessageInput** widget with a **SafeArea** widget -- `elevation`: elevation of the **StreamMessageInput** widget -- `shadow`: **Shadow** for the **StreamMessageInput** widget - -For more information see the [`StreamMessageInput` documentation](../stream_chat_flutter_core/stream_message_input_controller.mdx). - -### StreamMessageInput Examples - -Let's explore some examples of the functional differences when using the new `StreamMessageInput`. - -#### Basic Use - -Unless you want to programmatically manipulate the value of the message input, then there is no difference in how you would use the message input widget. - -The following code demonstrates the old way of creating a **ChannelPage** widget that displays a chat screen: - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: const ChannelHeader(), - body: Column( - children: const [ - Expanded( - child: MessageListView(), - ), - MessageInput(), - ], - ), - ); - } -} -``` - -In **v4** this is the same, the only difference being that all the Stream widgets are now prefixed with **Stream**. For example, **MessageListView** becomes **StreamMessageListView**, and so forth. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) => Scaffold( - appBar: const StreamChannelHeader(), - body: Column( - children: const [ - Expanded( - child: StreamMessageListView(), - ), - StreamMessageInput(), - ], - ), - ); -} -``` - -However, you can optionally pass in a **MessageInputController** in the **StreamMessageInput**, which gives extra control over the message input value. - -#### Thread Page - -The following code demonstrates the old way of creating a thread page: - -```dart -class ThreadPage extends StatelessWidget { - const ThreadPage({ - Key? key, - this.parent, - }) : super(key: key); - - final Message? parent; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: ThreadHeader( - parent: parent!, - ), - body: Column( - children: [ - Expanded( - child: MessageListView( - parentMessage: parent, - ), - ), - MessageInput( - parentMessage: parent, - ), - ], - ), - ); - } -} -``` - -In **v4** the only difference is the **Stream** prefix and the way that the parent message is passed to the message input: - -```dart -class ThreadPage extends StatelessWidget { - const ThreadPage({ - Key? key, - this.parent, - }) : super(key: key); - - final Message? parent; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: StreamThreadHeader( - parent: parent!, - ), - body: Column( - children: [ - Expanded( - child: StreamMessageListView( - parentMessage: parent, - ), - ), - StreamMessageInput( - messageInputController: MessageInputController( - message: Message(parentId: parent!.id), - ), - ), - ], - ), - ); - } -} -``` - -To send a thread message, you need to specify the message's parent ID for which you're creating a thread. - -#### Reply/Quote Message - -The following code demonstrates the old way of replying to a message: - -```dart -... - -void _reply(Message message) { - setState(() => _quotedMessage = message); -} - -... - -MessageInput - quotedMessage: _quotedMessage, - onQuotedMessageCleared: () { - setState(() => _quotedMessage = null); - }, -), -``` - -To reply to a message in **v4**: - -```dart -... - -void _reply(Message message) { - _messageInputController.quotedMessage = message; -} - -... - -StreamMessageInput( - messageInputController: _messageInputController, -), -``` - -The controller makes it much simpler to dynamically modify the message input. - -## Stream Chat Flutter Core - -Various changes have been made to the Core package, most notably, the introduction of all of the controllers mentioned above. - -These controllers replace the business logic implementations (Bloc). Please note that this is not related to the well-known Flutter Bloc package, but instead refers to the naming we used for our business logic components. - -In this version we're introducing controllers in place of their bloc counterparts: -**StreamChannelListController** in favor of **ChannelsBloc** -**StreamMessageSearchListController** in favor of **MessageSearchBloc** -**StreamUserListController** in favor of **UsersBloc** - -The Bloc components are deprecated in v4.0.0 but can still be used. They will be removed in the next major release (v5.0.0). - -Additionally, we also now have the **StreamMessageInputController**, as discussed above. This can be used outside of our UI package as well. - -Finally, the following Core builders are also deprecated as their functionality can be replaced using their controller counterparts: - -- ChannelListCore -- MessageSearchListCore -- UserListCore diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/slidable_channel_list_preview.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/slidable_channel_list_preview.mdx deleted file mode 100644 index 9385a986eb..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/slidable_channel_list_preview.mdx +++ /dev/null @@ -1,211 +0,0 @@ ---- -id: slidable_channel_list_preview -title: Slidable Channel List Preview ---- - -Slidable Channel List Preview - -### Introduction - -The default slidable behavior within the channel list has been removed in v4 of the Stream Chat Flutter SDK. -This guide will show you how you can easily add this functionality yourself. - -Please see our [full v4 migration guide](migration_guide_4_0.mdx) if you're migrating from an earlier version of the Stream Chat Flutter SDK. - -![Slidable demo](../assets/slidable_demo.jpg) - -### Prerequisites - -This guide assumes you are familiar with the Stream Chat SDK. -If you're new to Stream Chat Flutter, we recommend looking at our [getting started tutorial](https://getstream.io/chat/flutter/tutorial/). - -**Dependencies:** - -```dart -dependencies: - flutter: - sdk: flutter - stream_chat_flutter: ^4.0.0 - flutter_slidable: ^1.2.0 -``` - -⚠️ Note: The examples shown in this guide use the above packages and versions. - -### Example Code - Custom Stream Channel Item Builder - -In this example, you are doing a few important things in the ChannelListPage widget. You're: - -- Using the **flutter_slidable** package to easily add slide functionality. -- Passing in the `itemBuilder` argument for the **StreamChannelListView** widget. This gives access to the current **BuildContext**, **Channel**, and **StreamChannelListTile**, and allows you to create, or customize, the stream channel list tiles. -- Returning a Slidable widget with two CustomSlidableAction widgets - to delete a channel and show more options. These widgets come from the flutter_slidable package. -- Adding `onPressed` behaviour to call `showConfirmationDialog` and `showChannelInfoModalBottomSheet`. These methods come from the **`stream_chat_flutter`** package. They have a few different on-tap callbacks you can supply, for example, `onViewInfoTap`. Alternatively, you can create custom dialog screens from scratch. -- Using the **StreamChannelListController** to perform actions, such as, `deleteChannel`. - -```dart -import 'package:flutter/material.dart'; -import 'package:flutter_slidable/flutter_slidable.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -void main() async { - final client = StreamChatClient( - 's2dxdhpxd94g', - ); - - await client.connectUser( - User(id: 'super-band-9'), - '''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''', - ); - - 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: ChannelListPage( - client: client, - ), - ); - } -} - -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: SlidableAutoCloseBehavior( - child: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - itemBuilder: (context, channel, tile) { - final chatTheme = StreamChatTheme.of(context); - final backgroundColor = chatTheme.colorTheme.inputBg; - final canDeleteChannel = channel.ownCapabilities - .contains(PermissionType.deleteChannel); - return Slidable( - groupTag: 'channels-actions', - endActionPane: ActionPane( - extentRatio: canDeleteChannel ? 0.40 : 0.20, - motion: const BehindMotion(), - children: [ - CustomSlidableAction( - onPressed: (_) { - showChannelInfoModalBottomSheet( - context: context, - channel: channel, - onViewInfoTap: () { - Navigator.pop(context); - // Navigate to info screen - }, - ); - }, - backgroundColor: backgroundColor, - child: const Icon(Icons.more_horiz), - ), - if (canDeleteChannel) - CustomSlidableAction( - backgroundColor: backgroundColor, - child: StreamSvgIcon.delete( - color: chatTheme.colorTheme.accentError, - ), - onPressed: (_) async { - final res = await showConfirmationDialog( - context, - title: 'Delete Conversation', - question: - 'Are you sure you want to delete this conversation?', - okText: 'Delete', - cancelText: 'Cancel', - icon: StreamSvgIcon.delete( - color: chatTheme.colorTheme.accentError, - ), - ); - if (res == true) { - await _controller.deleteChannel(channel); - } - }, - ), - ], - ), - child: tile, - ); - }, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ), - ); -} - -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) => Scaffold( - appBar: const StreamChannelHeader(), - body: Column( - children: const [ - Expanded( - child: StreamMessageListView(), - ), - StreamMessageInput(), - ], - ), - ); -} -``` - -The above is the complete sample, and all you need for a basic implementation. diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/understanding_filters.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/understanding_filters.mdx deleted file mode 100644 index 120a7ac631..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/understanding_filters.mdx +++ /dev/null @@ -1,193 +0,0 @@ ---- -id: understanding_filters -title: Understanding Filters ---- - -Understanding Filters - -### Introduction - -Filters are used to get a specific subset of objects (channels, users, messages, members, etc) which -fit the conditions specified. Earlier versions of the SDK contained String-based filters which are now replaced by type-safe -filters. This guide aims to explain the different types of filters and how to use them. - -### Types Of Filters - -#### Filter.equal - -The 'equal' filter gets the objects where the given key has the specified value. - -```dart -Filter.equal('type', 'messaging'), -``` - -#### Filter.notEqual - -The `notEqual` filter gets the objects where the given key does not have the specified value. - -```dart -Filter.notEqual('type', 'messaging'), -``` - -#### Filter.greater - -The 'greater' filter gets the objects where the given key has a higher value than the specified value. - -```dart -Filter.greater('count', 5), -``` - -#### Filter.greaterOrEqual - -The 'greaterOrEqual' filter gets the objects where the given key has an equal or higher value than the specified value. - -```dart -Filter.greaterOrEqual('count', 5), -``` - -#### Filter.less - -The 'less' filter gets the objects where the given key has a lesser value than the specified value. - -```dart -Filter.less('count', 5), -``` - -#### Filter.lessOrEqual - -The 'lessOrEqual' filter gets the objects where the given key has a lesser or equal value than the specified value. - -```dart -Filter.lessOrEqual('count', 5), -``` - -#### Filter.in_ - -The `in_` filter allows getting objects where the key matches any in a specified array. - -```dart -Filter.in_('members', [user.id]) -``` - -:::note -Since `in` is a keyword in Dart, the filter has an underscore added. This does not apply to the `notIn` -keyword. -::: - -#### Filter.notIn - -The `notIn` filter allows getting objects where the key matches none in a specified array. - -```dart -Filter.notIn('members', [user.id]) -``` - -#### Filter.query - -The 'query' filter matches values by performing text search with the specified value. - -```dart -Filter.query('name', 'demo') -``` - -#### Filter.autoComplete - -The 'autoComplete' filter matches values with the specified prefix. - -```dart -Filter.autoComplete('name', 'demo') -``` - -#### Filter.exists - -The 'exists' filter matches values that exist, or don't exist, based on the specified boolean value. - -```dart -Filter.exists('name') -``` - -#### Filter.notExists - -The `notExists` filter checks if the specified key doesn't exist. This is a simplified call to `Filter.exists` -with the value set to false. - -```dart -Filter.notExists('name') -``` - -#### Filter.contains - -The 'contains' filter matches any list that contains the specified value. - -```dart -Filter.contains('teams', 'red') -``` - -#### Filter.empty - -The 'empty' filter constructor returns an empty filter. It's the equivalent of an empty map `{}`; - -```dart -Filter.empty(); -``` - -#### Filter.raw - -The 'raw' filter constructor lets you specify a raw filter. We suggest using this only if you can't manage to build what you want using the other constructors. - -```dart -Filter.raw(value: { - 'members': [ - ..._selectedUsers.map((e) => e.id), - chatState.currentUser!.id, - ], - 'distinct': true, -}); -``` - -#### Filter.custom - -The 'custom' filter is used to create a custom filter in case it does not exists or it's not been added to the SDK yet. -Note that the filter must be supported by the Stream backend in order to work. - -```dart -Filter.custom( - operator: '\$max', - value: 10, -) -``` - -### Group Queries - -#### Filter.and - -The 'and' operator combines multiple queries. - -```dart -final filter = Filter.and([ - Filter.equal('type', 'messaging'), - Filter.in_('members', [user.id]) -]) -``` - -#### Filter.or - -Combines the provided filters and matches the values matched by at least one of the filters. - -```dart -final filter = Filter.or([ - Filter.in_('bannedUsers', [user.id]), - Filter.in_('shadowBannedUsers', [user.id]) -]) -``` - -#### Filter.nor - -Combines the provided filters and matches the values not matched by all the filters. - -```dart -final filter = Filter.nor([ - Filter.in_('bannedUsers', [user.id]), - Filter.in_('shadowBannedUsers', [user.id]) -]) -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/user_token_generation_with_firebase_auth.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/user_token_generation_with_firebase_auth.mdx deleted file mode 100644 index 0012dbda05..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/guides/user_token_generation_with_firebase_auth.mdx +++ /dev/null @@ -1,447 +0,0 @@ ---- -id: token_generation_with_firebase -title: User Token Generation With Firebase Auth and Cloud Functions ---- - -Securely generate Stream Chat user tokens using Firebase Authentication and Cloud Functions. - -:::note -This guide assumes that you are familiar with Firebase Authentication and Cloud Functions for Flutter and using the Flutter Stream Chat SDK. -::: - -### Introduction - -In this guide, you'll explore how you can use Firebase Auth as an authentication provider and create Firebase Cloud functions to securely -generate Stream Chat user tokens. - -You will use Stream's [NodeJS client](https://getstream.io/chat/docs/node/?language=javascript) for Stream account creation and -token generation, and [Flutter Cloud Functions for Firebase](https://firebase.flutter.dev/docs/functions/overview) to invoke the cloud functions -from your Flutter app. - -Stream supports several different [backend clients](https://getstream.io/chat/sdk/#backend-clients) to integrate with your server. This guide only shows an easy way to integrate Stream Chat authentication using Firebase and Flutter. - -### Flutter Firebase - -See the [Flutter Firebase getting started](https://firebase.flutter.dev/docs/overview) docs for setup and installation instructions. - -You will also need to add the [Flutter Firebase Authentication](https://firebase.flutter.dev/docs/auth/overview), and [Flutter Firebase Cloud Functions](https://firebase.flutter.dev/docs/functions/overview) packages to your app. Depending on the platform that you target, there may be specific configurations that you need to do. - -#### Starting Code - -The following code shows a basic application with **FirebaseAuth** and **FirebaseFunctions**. - -You will extend this later to execute cloud functions. - -```dart -import 'package:cloud_functions/cloud_functions.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:flutter/material.dart'; -import 'dart:async'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - await Firebase.initializeApp(); - runApp(MyApp()); -} - -class MyApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - body: Auth(), - ), - ); - } -} - -class Auth extends StatefulWidget { - Auth({Key? key}) : super(key: key); - - @override - _AuthState createState() => _AuthState(); -} - -class _AuthState extends State { - late FirebaseAuth auth; - late FirebaseFunctions functions; - - @override - void initState() { - super.initState(); - auth = FirebaseAuth.instance; - functions = FirebaseFunctions.instance; - } - - final email = 'test@getstream.io'; - final password = 'password'; - - Future createAccount() async { - // Create Firebase account - await auth.createUserWithEmailAndPassword(email: email, password: password); - print('Firebase account created'); - } - - Future signIn() async { - // Sign in with Firebase - await auth.signInWithEmailAndPassword(email: email, password: password); - print('Firebase signed in'); - } - - Future signOut() async { - // Revoke Stream chat token. - final callable = functions.httpsCallable('revokeStreamUserToken'); - await callable(); - print('Stream user token revoked'); - } - - @override - Widget build(BuildContext context) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - AuthenticationState( - streamUser: auth.authStateChanges(), - ), - ElevatedButton( - onPressed: createAccount, - child: Text('Create account'), - ), - ElevatedButton( - onPressed: signIn, - child: Text('Sign in'), - ), - ElevatedButton( - onPressed: signOut, - child: Text('Sign out'), - ), - ], - ), - ); - } -} - -class AuthenticationState extends StatelessWidget { - const AuthenticationState({ - Key? key, - required this.streamUser, - }) : super(key: key); - - final Stream streamUser; - - @override - Widget build(BuildContext context) { - return StreamBuilder( - stream: streamUser, - builder: (context, snapshot) { - if (snapshot.hasData) { - return (snapshot.data != null) - ? Text('Authenticated') - : Text('Not Authenticated'); - } - return Text('Not Authenticated'); - }, - ); - } -} - -``` - -Running the above will give this: - -![](../assets/authentication_demo_app.jpg) - -The `Auth` widget handles all of the authentication logic. It initializes a `FirebaseAuth.instance` and uses that -in the `createAccount`, `signIn` and `signOut` methods. There is a button to invoke each of these methods. - -The `FirebaseFunctions.instance` will be used later in this guide. - -The `AuthenticationState` widget listens to `auth.authStateChanges()` to display a message -indicating if a user is authenticated. - -### Firebase Cloud Functions - -Firebase Cloud Functions allows you to extend Firebase with custom operations that an event can trigger: -- **Internal event**: For example, when creating a new Firebase account this is automatically triggered. -- **External event**: For example, directly calling a cloud function from your Flutter application. - -To set up your local environment to deploy cloud functions, please see the -[Cloud Functions getting started](https://firebase.flutter.dev/docs/overview) docs. - -After initializing your project with cloud functions, you should have a **functions** folder in your project, including a `package.json` file. - -There should be two dependencies already added, **firebase-admin** and **firebase-functions**. You will also need to add the **stream-chat** dependency. - -Navigate to the **functions** folder and run `npm install stream-chat --save-prod`. - -This will install the node module and add it as a dependency to `package.json`. - -Now open `index.js` and add the following (this is the complete example): - -```js -const StreamChat = require('stream-chat').StreamChat; -const functions = require("firebase-functions"); -const admin = require("firebase-admin"); - -admin.initializeApp(); - -const serverClient = StreamChat.getInstance(functions.config().stream.key, functions.config().stream.secret); - - -// When a user is deleted from Firebase their associated Stream account is also deleted. -exports.deleteStreamUser = functions.auth.user().onDelete((user, context) => { - return serverClient.deleteUser(user.uid); -}); - -// Create a Stream user and return auth token. -exports.createStreamUserAndGetToken = functions.https.onCall(async (data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - // Create user using the serverClient. - await serverClient.upsertUser({ - id: context.auth.uid, - name: context.auth.token.name, - email: context.auth.token.email, - image: context.auth.token.image, - }); - - /// Create and return user auth token. - return serverClient.createToken(context.auth.uid); - } catch (err) { - console.error(`Unable to create user with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not create Stream user"); - } - } -}); - -// Get Stream user token. -exports.getStreamUserToken = functions.https.onCall((data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - return serverClient.createToken(context.auth.uid); - } catch (err) { - console.error(`Unable to get user token with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not get Stream user"); - } - } -}); - -// Revoke the authenticated user's Stream chat token. -exports.revokeStreamUserToken = functions.https.onCall((data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - return serverClient.revokeUserToken(context.auth.uid); - } catch (err) { - console.error(`Unable to revoke user token with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not get Stream user"); - } - } -}); - -``` - -First, you import the necessary packages and call `admin.initializeApp();` to set up Firebase cloud functions. - -Next, you initialize the **StreamChat** server client by calling `StreamChat.getInstance`. This function requires your Stream app's -**token** and **secret**. You can get this from the Stream Dashboard for your app. - -Set these values as environment data on Firebase Functions. - -```bash - firebase functions:config:set stream.key="app-key" stream.secret="app-secret" -``` - -*Replace **app-key** and **app-secret** with the values for your Stream app.* - -This creates an object of **stream** with properties **key** and **secret**. To access this environment -data use `functions.config().stream.key` and `functions.config().stream.secret`. - -See the [Firebase environment configuration](https://firebase.google.com/docs/functions/config-env) -documentation for additional information. - -To deploy these functions to Firebase, run: - -```bash -firebase deploy --only functions -``` - -### Create a Stream User and Get the User's Token - -In the `createStreamUserAndGetToken` cloud function you create an `onCall` HTTPS handler, which exposes -a cloud function that can be invoked from your Flutter app. - -```js -// Create a Stream user and return auth token. -exports.createStreamUserAndGetToken = functions.https.onCall(async (data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - // Create user using the serverClient. - await serverClient.upsertUser({ - id: context.auth.uid, - name: context.auth.token.name, - email: context.auth.token.email, - image: context.auth.token.image, - }); - - /// Create and return user auth token. - return serverClient.createToken(context.auth.uid); - } catch (err) { - console.error(`Unable to create user with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not create Stream user"); - } - } -}); -``` - -This function first does a check to see that the client that calls it is authenticated, -by ensuring that `context.auth` is not null. If it is null, then it throws an `HttpsError` with a descriptive -message. This error can be caught in your Flutter application. - -If the caller is authenticated the function proceeds to use the `serverClient` to create a new Stream Chat -user by calling the `upsertUser` method and passing in some user data. It uses the authenticated caller's **`uid`** as an **id**. - -After the user is created it generates a token for that user. This token is then returned to the caller. - -To call this from Flutter, you will need to use the `cloud_functions` package. - -Update the **`createAccount`** method in your Flutter code to the following: - -```dart -Future createAccount() async { - // Create Firebase account - await auth.createUserWithEmailAndPassword(email: email, password: password); - print('Firebase account created'); - - // Create Stream user and get token - final callable = functions.httpsCallable('createStreamUserAndGetToken'); - final results = await callable(); - print('Stream account created, token: ${results.data}'); -} -``` - -Calling this method will do the following: -1. Create a new Firebase User and authenticate that user. -2. Call the `createStreamUserAndGetToken` cloud function and get the Stream user token for the authenticated user. - -As you can see, calling a cloud function is easy and will also send all the necessary user authentication information (such as the UID) -in the request. - -Once you have the Stream user token, you can authenticate your Stream Chat user as you normally would. - -Please see our [initialization documentation](https://getstream.io/chat/docs/flutter-dart/init_and_users/?language=dart) for more information. - -As you can see below, the User ID matches on both Firebase's and Stream's user database. - -##### Firebase Authentication Database - -![Firebase Auth Database with new user created](../assets/firebase_authentication_dashboard.jpg) - -##### Stream Chat User Database - -![Stream chat user database new account created](../assets/stream_chat_user_database.jpg) - - -### Get the Stream User Token - -The `getStreamUserToken` cloud function is very similar to the `createStreamUserAndGetToken` function. The only difference is -that it only creates a user token and does not create a new user account on Stream. - -Update the **`signIn`** method in your Flutter code to the following: - -```dart -Future signIn() async { - // Sign in with Firebase - await auth.signInWithEmailAndPassword(email: email, password: password); - print('Firebase signed in'); - - // Get Stream user token - final callable = functions.httpsCallable('getStreamUserToken'); - final results = await callable(); - print('Stream user token retrieved: ${results.data}'); -} -``` - -Calling this method will do the following: -1. Sign in using Firebase Auth. -2. Call the `getStreamUserToken` cloud function to get a Stream user token. - -:::note -The user needs to be authenticated to call this cloud function. Otherwise, the function will throw -the **failed-precondition** error that you specified. -::: - -### Revoke Stream User Token - -You may also want to revoke the Stream user token if you sign out from Firebase. - -Update the `signOut` method in your Flutter code to the following: - -```dart -Future signOut() async { - // Revoke Stream user token. - final callable = functions.httpsCallable('revokeStreamUserToken'); - await callable(); - print('Stream user token revoked'); - - // Sign out Firebase. - await auth.signOut(); - print('Firebase signed out'); -} -``` -:::note -Call the cloud function before signing out from Firebase. -::: - -### Delete Stream User - -When deleting a Firebase user account, it would make sense also to delete the -associated Stream user account. - -The cloud function looks like this: - -```js -// When a user is deleted from Firebase their associated Stream account is also deleted. -exports.deleteStreamUser = functions.auth.user().onDelete((user, context) => { - return serverClient.deleteUser(user.uid); -}); -``` - -In this function, you are listening to delete events on Firebase auth. When an account is deleted, this function will be triggered, and you can get the -user's **`uid`** and call the `deleteUser` method on the `serverClient`. - -This is not an external cloud function; it can only be triggered when an -account is deleted. - -### Conclusion - -In this guide, you have seen how to securely create Stream Chat tokens using -Firebase Authentication and Cloud Functions. - -The principles shown in this guide can be applied to your preferred authentication -provider and cloud architecture of choice. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/_category_.json b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/_category_.json deleted file mode 100644 index 242afb7be9..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Stream Chat Flutter", - "position": 3 -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/introduction.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/introduction.mdx deleted file mode 100644 index 8be1ffabe0..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/introduction.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -id: introduction -title: Introduction ---- - -Understanding The UI Package Of The Flutter SDK - -### What function does `stream_chat_flutter` serve? - -The UI SDK (`stream_chat_flutter`) contains official Flutter components for Stream Chat, a service for building chat applications. - -While the Stream Chat service provides the backend for messaging and the LLC provides an easy way to -use it in your Flutter apps, we wanted to make sure that adding Chat functionality to your app was as quick as possible. - -The UI package is built on top of the low-level client and the core package and allows you to build a -full fledged app with either the inbuilt components, modify existing components, or easily add widgets -of your own to match your app's style better. diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/setup.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/setup.mdx deleted file mode 100644 index 9203e837bf..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/setup.mdx +++ /dev/null @@ -1,47 +0,0 @@ ---- -id: setup -title: Setup ---- - -Understanding Setup For `stream_chat_flutter` - -### Add pub.dev dependency - -First, you need to add the `stream_chat_flutter` dependency to your `pubspec.yaml`. - -You can either run this command: - -```shell -flutter pub add stream_chat_flutter -``` - -OR - -Add this line in the dependencies section of your pubspec.yaml after substituting latest version: - -```yaml -dependencies: - stream_chat_flutter: ^latest_version -``` - -You can find the package details on [pub.dev](https://pub.dev/packages/stream_chat_flutter). - -### Details On Platform Support - -`stream_chat_flutter` was originally created for Android and iOS mobile platforms. As Flutter matured, -support for additional platforms was added and the package now has experimental support for web and desktop as -[detailed here](https://getstream.io/blog/announcing-experimental-multi-platform-support-for-the-stream-flutter-sdk/). - -However, platforms other than mobile may have additional constraints due to not supporting all plugins, -which will be addressed by the respective plugin creators over time. - -### Setup: iOS - -The library uses [flutter file picker plugin](https://github.com/miguelpruivo/flutter_file_picker) to pick files from the os. -Follow [this wiki](https://github.com/miguelpruivo/flutter_file_picker/wiki/Setup#ios) to fulfill iOS requirements. - -We also use [`video_player`](https://pub.dev/packages/video_player) to reproduce videos. -Follow [this guide](https://pub.dev/packages/video_player#installation) to fulfill the requirements. - -To pick images from the camera, we use the [`image_picker`](https://pub.dev/packages/image_picker) plugin. -Follow [these instructions](https://pub.dev/packages/image_picker#ios) to check the requirements. diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_channel_grid_view.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_channel_grid_view.mdx deleted file mode 100644 index 87ad4dc908..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_channel_grid_view.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: stream_channel_grid_view -title: StreamChannelGridView ---- - -A Widget For Displaying A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelGridView-class.html) - -### Background - -The `StreamChannelGridView` widget allows displaying a list of channels to a user in a `GridView`. - -:::note -Make sure to check the [StreamChannelListView](./stream_channel_list_view.mdx) documentation to know how to show results in a `ListView`. -::: - -### Basic Example - -Here is a basic example of the `StreamChannelGridView` widget. It consists of the main widget itself, a `StreamChannelListController` to control the list of channels and a callback to handle the tap of a channel. - -```dart -class ChannelGridPage extends StatefulWidget { - const ChannelGridPage({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - State createState() => _ChannelGridPageState(); -} - -class _ChannelGridPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelGridView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -This example by default displays the channels that a user is a part of. Now let's look at customizing -the widget. diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_channel_header.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_channel_header.mdx deleted file mode 100644 index d96c128802..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_channel_header.mdx +++ /dev/null @@ -1,83 +0,0 @@ ---- -id: stream_channel_header -title: StreamChannelHeader ---- - -A Widget To Display Common Channel Details - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelHeader-class.html) - -![](../assets/channel_header.png) - -### Background - -When a user opens a channel, it is helpful to provide context of which channel they are in. This may -be in the form of a channel name or the users in the channel. Along with that, there also needs to be -a way for the user to look at more details of the channel (media, pinned messages, actions, etc.) and -preferably also a way to navigate back to where they came from. - -To encapsulate all of this functionality into one widget, the Flutter SDK contains a `StreamChannelHeader` -widget which provides these out of the box. - -### Basic Example - -Let's just add a `StreamChannelHeader` to a page with a `StreamMessageListView` and a `StreamMessageInput` to display -and send messages. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: StreaChannelHeader(), - body: Column( - children: [ - Expanded( - child: StreamMessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, - ), - ), - StreamMessageInput(), - ], - ), - ); - } -} -``` - -### Customizing Parts Of The Header - -The header works like a `ListTile` widget. - -Use the `title`, `subtitle`, `leading`, or `actions` parameters to substitute the widgets for your own. - -```dart -//... -StreamChannelHeader( - title: Text('My Custom Name'), -), -``` - -![](../assets/channel_header_custom_title.png) - -### Showing Connection State - -The `StreamChannelHeader` can also display connection state below the tile which shows the user if they -are connected or offline, etc. on connection events. - -To enable this, use the `showConnectionStateTile` property. - -```dart -//... -StreamChannelHeader( - showConnectionStateTile: true, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_channel_list_header.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_channel_list_header.mdx deleted file mode 100644 index 3aab2b5a4b..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_channel_list_header.mdx +++ /dev/null @@ -1,117 +0,0 @@ ---- -id: stream_channel_list_header -title: StreamChannelListHeader ---- - -A Header Widget For A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelListHeader-class.html) - -![](../assets/channel_list_header.png) - -### Background - -A common pattern for most messaging apps is to show a list of Channels (chats) on the first screen -and navigate to an individual one on being clicked. On this first page where the list of channels are -displayed, it is usual to have functionality such as adding a new chat, display the user logged in, etc. - -To encapsulate all of this functionality into one widget, the Flutter SDK contains a `StreamChannelListHeader` -widget which provides these out of the box. - -### Basic Example - -This is a basic example of a page which has a `StreamChannelListView` and a `StreamChannelListHeader` to recreate a -common Channels Page. - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - appBar: StreamChannelListHeader(), - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -### Customizing Parts Of The Header - -The header works like a `ListTile` widget. - -Use the `titleBuilder`, `subtitle`, `leading`, or `actions` parameters to substitute the widgets for your own. - -```dart -//... -StreamChannelListHeader( - subtitle: Text('My Custom Subtitle'), -), -``` - -![](../assets/channel_list_header_custom_subtitle.png) - -The `titleBuilder` parameter helps you build different titles depending on the connection state: - -```dart -//... -StreamChannelListHeader( - titleBuilder: (context, status, client) { - switch(status) { - /// Return your title widget - } - }, -), -``` - -### Showing Connection State - -The `StreamChannelListHeader` can also display connection state below the tile which shows the user if they -are connected or offline, etc. on connection events. - -To enable this, use the `showConnectionStateTile` property. - -```dart -//... -StreamChannelListHeader( - showConnectionStateTile: true, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_channel_list_view.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_channel_list_view.mdx deleted file mode 100644 index 1b8c04d2a7..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_channel_list_view.mdx +++ /dev/null @@ -1,106 +0,0 @@ ---- -id: stream_channel_list_view -title: StreamChannelListView ---- - -A Widget For Displaying A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelListView-class.html) - -![](../assets/channel_list_view.png) - -### Background - -Channels are fundamental elements of Stream Chat and constitute shared spaces which allow users to -message each other. - -1:1 conversations and groups are both examples of channels, albeit with some (distinct/non-distinct) -differences. Displaying the list of channels that a user is a part of is a pattern present in most messaging apps. - -The `StreamChannelListView` widget allows displaying a list of channels to a user. By default, this is NOT -ONLY the channels that the user is a part of. This section goes into setting up and using a `StreamChannelListView` -widget. - -:::note -Make sure to check the [StreamChannelListController](../stream_chat_flutter_core/stream_channel_list_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamChannelListView`. -::: - -### Basic Example - -Here is a basic example of the `StreamChannelListView` widget. It consists of the main widget itself, a `StreamChannelListController` to control the list of channels and a callback to handle the tap of a channel. - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -This example by default displays the channels that a user is a part of. Now let's look at customizing -the widget. - -### Customizing the Channel Preview - -A common aspect of the widget needed to be tweaked according to each app is the Channel Preview (the -Channel tile in the list). To do this, we use the `itemBuilder` parameter like this: - -```dart -StreamChannelListView( - ... - itemBuilder: (context, channels, index, defaultTile) { - return ListTile( - tileColor: Colors.amberAccent, - title: Center( - child: StreamChannelName(channel: channels[index]), - ), - ); - }, -), -``` - -Which gives you a new Channel preview in the list: - -![](../assets/channel_preview.png) diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_chat_and_theming.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_chat_and_theming.mdx deleted file mode 100644 index 422639cf2d..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_chat_and_theming.mdx +++ /dev/null @@ -1,70 +0,0 @@ ---- -id: stream_chat_and_theming -title: StreamChat And Theming ---- - -Understanding How To Customize Widgets Using `StreamChatTheme` - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChatTheme-class.html) and [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChatThemeData-class.html) - -### Background - -Stream's UI SDK makes it easy for developers to add custom styles and attributes to our widgets. Like most Flutter frameworks, Stream exposes a dedicated widget for theming. - -Using `StreamChatTheme`, users can customize most aspects of our UI widgets by setting attributes using `StreamChatThemeData`. - -Similar to the `Theme` and `ThemeData` in Flutter, Stream Chat uses a top level [inherited widget](https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html) to provide theming information throughout your application. This can be optionally set at the top of your application tree or at a localized point in your widget sub-tree. - -If you'd like to customize the look and feel of Stream chat across your entire application, we recommend setting your theme at the top level. Conversely, users can customize specific screens or widgets by wrapping components in a `StreamChatTheme`. - -### A closer look at StreamChatThemeData - -Looking at the constructor for `StreamChatThemeData`, 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 `ChannelHeader`, `MessageInputs`, etc. have been broken up into smaller theme objects. - -```dart -factory StreamChatThemeData({ - Brightness? brightness, - TextTheme? textTheme, - ColorTheme? colorTheme, - ChannelListHeaderTheme? channelListHeaderTheme, - ChannelPreviewTheme? channelPreviewTheme, - ChannelTheme? channelTheme, - MessageTheme? otherMessageTheme, - MessageTheme? ownMessageTheme, - MessageInputTheme? messageInputTheme, - Widget Function(BuildContext, Channel)? defaultChannelImage, - Widget Function(BuildContext, User)? defaultUserImage, - IconThemeData? primaryIconTheme, - List? reactionIcons, - }); -``` - -### Stream Chat Theme in use - -Let's take a look at customizing widgets using `StreamChatTheme`. In the example below, we can change the default color theme to yellow and override the channel header's typography and colors. - -```dart -builder: (context, child) => StreamChat( - client: client, - child: child, - streamChatThemeData: StreamChatThemeData( - colorTheme: ColorTheme.light( - primaryAccent: const Color(0xffffe072), - ), - channelTheme: ChannelTheme( - channelHeaderTheme: ChannelHeaderTheme( - color: const Color(0xffd34646), - title: TextStyle( - color: Colors.white, - ), - ), - ), - ), - ), -``` - -We are creating this class at the very top of our widget tree using the `streamChatThemeData` parameter found in the `StreamChat` widget. - -![](../assets/using_theme.jpg) diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_message_input.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_message_input.mdx deleted file mode 100644 index 37693332ef..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_message_input.mdx +++ /dev/null @@ -1,112 +0,0 @@ ---- -id: stream_message_input -title: StreamMessageInput ---- - -A Widget Dealing With Everything Related To Sending A Message - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageInput-class.html) - -![](../assets/message_input.png) - -### Background - -In Stream Chat, we can send messages in a channel. However, sending a message isn't as simple as adding -a `TextField` and logic for sending a message. It involves additional processes like addition of media, -quoting a message, adding a custom command like a GIF board, and much more. Moreover, most apps also -need to customize the input to match their theme, overall color and structure pattern, etc. - -To do this, we created a `StreamMessageInput` widget which abstracts all expected functionality a modern input -needs - and allows you to use it out of the box. - -### Basic Example - -A `StreamChannel` is required above the widget tree in which the `StreamMessageInput` is rendered since the channel is -where the messages sent actually go. Let's look at a common example of how we could use the `StreamMessageInput`: - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: StreaChannelHeader(), - body: Column( - children: [ - Expanded( - child: StreamMessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, - ), - ), - StreamMessageInput(), - ], - ), - ); - } -} -``` - -It is common to put this widget in the same page of a `StreamMessageListView` as the bottom widget. - -:::note -Make sure to check the [StreamMessageInputController](../stream_chat_flutter_core/stream_message_input_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamMessageInput`. -::: - -### Adding Custom Actions - -By default, the `StreamMessageInput` has two actions: one for attachments and one for commands like Giphy. -To add your own action, we use the `actions` parameter like this: - -```dart -StreamMessageInput( - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20.0, - color: StreamChatTheme.of(context).colorTheme.grey, - ), - onTap: () { - // Do something here - }, - ), - ], -), -``` - -This will add on your action to the existing ones. - -### Disable Attachments - -To disable attachments being added to the message, set the `disableAttachments` parameter to true. - -```dart -StreamMessageInput( - disableAttachments: true, -), -``` - -### Changing Position Of MessageInput Components - -You can also change the position of the TextField, actions and 'send' button relative to each other. - -To do this, use the `actionsLocation` or `sendButtonLocation` parameters which help you decide the location -of the buttons in the input. - -For example, if we want the actions on the right and the send button inside the TextField, we can do: - -```dart -StreamMessageInput( - sendButtonLocation: SendButtonLocation.inside, - actionsLocation: ActionsLocation.right, -), -``` - -![](../assets/message_input_change_position.png) diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_message_list_view.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_message_list_view.mdx deleted file mode 100644 index 0bbc42f6a8..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_message_list_view.mdx +++ /dev/null @@ -1,91 +0,0 @@ ---- -id: stream_message_list_view -title: StreamMessageListView ---- - -A Widget For Displaying A List Of Messages - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageListView-class.html) - -![](../assets/message_list_view.png) - -### Background - -Every channel can contain a list of messages sent by users inside it. The `StreamMessageListView` widget -displays the list of messages inside a particular channel along with possible attachments and -other message attributes (if the message is pinned for example). This sets it apart from the `StreamMessageSearchListView` -which may not contain messages only from a single channel and is used to search for messages across -many. - -### Basic Example - -The `StreamMessageListView` shows the list of messages of the current channel. It has inbuilt support for -common messaging functionality: displaying and editing messages, adding / modifying reactions, support -for quoting messages, pinning messages, and more. - -An example of how you can use the `StreamMessageListView` is: - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: StreamChannelHeader(), - body: Column( - children: [ - Expanded( - child: StreamMessageListView(), - ), - StreamMessageInput(), - ], - ), - ); - } -} -``` - -### Enable Threads - -Threads are made of a parent message and replies linked to it. To enable threading, the SDK requires you -to supply a `threadBuilder` which will supply the page when the thread is clicked. - -```dart -StreamMessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, -), -``` - -![](../assets/message_list_view_threads.png) - -The `StreamMessageListView` itself can render the thread by supplying the `parentMessage` parameter. - -```dart -StreamMessageListView( - parentMessage: parent, -), -``` - -### Building Custom Messages - -You can also supply your own implementation for displaying messages using the `messageBuilder` parameter. - -:::note -To customize the existing implementation, look at the `StreamMessageWidget` documentation instead. -::: - -```dart -StreamMessageListView( - messageBuilder: (context, details, messageList, defaultImpl) { - // Your implementation of the message here - // E.g: return Text(details.message.text ?? ''); - }, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_message_search_grid_view.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_message_search_grid_view.mdx deleted file mode 100644 index 030a271a04..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_message_search_grid_view.mdx +++ /dev/null @@ -1,54 +0,0 @@ ---- -id: stream_message_search_grid_view -title: StreamMessageSearchGridView ---- - -A Widget To Search For Messages Across Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageSearchGridView-class.html) - -### Background - -The `StreamMessageSearchGridView` widget allows displaying a list of searched messages in a `GridView`. - -:::note -Make sure to check the [StreamMessageSearchListView](./stream_message_search_list_view.mdx) documentation to know how to show results in a `ListView`. -::: - -### Basic Example - -```dart -class StreamMessageSearchPage extends StatefulWidget { - const StreamMessageSearchPage({ - Key? key, - required this.client, - }) : super(key: key);` - - final StreamChatClient client; - - @override - State createState() => _StreamMessageSearchState(); -} - -class _StreamMessageSearchState extends State { - late final _controller = StreamMessageSearchListController( - client: widget.client, - limit: 20, - filters: Filter.in_('members', [StreamChat.of(context).user!.id],), - searchQuery: 'your query here', - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: StreamMessageSearchGridView( - controller: _controller, - ), - ); -} -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_message_search_list_view.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_message_search_list_view.mdx deleted file mode 100644 index 89bd2a77be..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_message_search_list_view.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: stream_message_search_list_view -title: StreamMessageSearchListView ---- - -A Widget To Search For Messages Across Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageSearchListView-class.html) - -![](../assets/message_search_list_view.png) - -### Background - -Users in Stream Chat can have several channels and it can get hard to remember which channel has the -message they are searching for. As such, there needs to be a way to search for a message across multiple -channels. This is where `StreamMessageSearchListView` comes in. - -:::note -Make sure to check the [StreamMessageSearchListController](../stream_chat_flutter_core/stream_message_search_list_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamMessageSearchListView`. -::: - -### Basic Example - -While the `StreamMessageListView` is tied to a certain `StreamChannel`, a `StreamMessageSearchListView` is not. - -```dart -class StreamMessageSearchPage extends StatefulWidget { - const StreamMessageSearchPage({ - Key? key, - required this.client, - }) : super(key: key);` - - final StreamChatClient client; - - @override - State createState() => _StreamMessageSearchState(); -} - -class _StreamMessageSearchState extends State { - late final _controller = StreamMessageSearchListController( - client: widget.client, - limit: 20, - filters: Filter.in_('members', [StreamChat.of(context).user!.id],), - searchQuery: 'your query here', - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: StreamMessageSearchListView( - controller: _controller, - ), - ); -} -``` - -### Customize The Result Tiles - -You can use your own widget for the result items using the `itemBuilder` parameter. - -```dart -StreamMessageSearchListView( - // ... - itemBuilder: (context, responses, index, defaultWidget) { - return Text(responses[index].message.text); - }, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_message_widget.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_message_widget.mdx deleted file mode 100644 index 10d64166f6..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_message_widget.mdx +++ /dev/null @@ -1,96 +0,0 @@ ---- -id: stream_message_widget -title: StreamMessageWidget ---- - -A Widget For Displaying Messages And Attachments - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageWidget-class.html) - -### Background - -There are several things that need to be displayed with text in a message in a modern messaging app: -attachments, highlights if the message is pinned, user avatars of the sender, etc. - -To encapsulate all of this functionality into one widget, the Flutter SDK contains a `StreamMessageWidget` -widget which provides these out of the box. - -### Basic Example (Modifying `StreamMessageWidget` in `StreamMessageListView`) - -Primarily, the `StreamMessageWidget` is used in the `StreamMessageListView`. To customize only a few properties -of the `StreamMessageWidget` without supplying all other properties, the `messageBuilder` builder supplies -a default implementation of the widget for us to modify. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: StreamMessageListView( - messageBuilder: (context, details, messageList, defaultMessageWidget) { - return defaultMessageWidget.copyWith( - showThreadReplyIndicator: false, - ); - }, - ), - ); - } -} -``` - -### Building A Custom Attachment - -When a custom attachment type (location, audio, etc.) is sent, the MessageWidget also needs to know -how to build it. For this purpose, we can use the `customAttachmentBuilders` parameter. - -As an example, if a message has a attachment type 'location', we do: - -```dart -StreamMessageWidget( - //... - customAttachmentBuilders: { - 'location': (context, message, attachments) { - var attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'], - attachments[0].extraData['longitude'], - ), - ); - - return wrapAttachmentWidget(context, attachmentWidget, null, true, BorderRadius.circular(8.0)); - } - }, -) -``` - -You can also override the builder for existing attachment types like `image` and `video`. - -### Show User Avatar For Messages - -You can decide to show, hide, or remove user avatars of the sender of the message. To do this, set -the `showUserAvatar` property like this: - -```dart -StreamMessageWidget( - //... - showUserAvatar = DisplayWidget.show, -) -``` - -### Reverse the message - -In most cases, `StreamMessageWidget` needs to be a different orientation depending upon if the sender is the -user or someone else. - -For this, we use the `reverse` parameter to change the orientation of the message: - -```dart -StreamMessageWidget( - //... - reverse = true, -) -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_user_grid_view.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_user_grid_view.mdx deleted file mode 100644 index b15aec3ef4..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_user_grid_view.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: stream_user_grid_view -title: StreamUserGridView ---- - -A Widget For Displaying And Selecting Users - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamUserGridView-class.html) - -### Background - -The `StreamUserGridView` widget allows displaying a list of users in a `GridView`. - -:::note -Make sure to check the [StreamUserListView](./stream_user_list_view.mdx) documentation to know how to show results in a `ListView`. -::: - -### Basic Example - -```dart -class UserGridPage extends StatefulWidget { - const UserGridPage({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - State createState() => _UserGridPageState(); -} - -class _UserGridPageState extends State { - late final _controller = StreamUserListController( - client: widget.client, - limit: 25, - filter: Filter.and([ - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]), - sort: [ - SortOption( - 'name', - direction: 1, - ), - ], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamUserGridView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_user_list_view.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_user_list_view.mdx deleted file mode 100644 index ebc56b87b5..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter/stream_user_list_view.mdx +++ /dev/null @@ -1,93 +0,0 @@ ---- -id: stream_user_list_view -title: StreamUserListView ---- - -A Widget For Displaying And Selecting Users - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamUserListView-class.html) - -![](../assets/user_list_view.png) - -### Background - -A list of users is required for many different purposes: showing a list of users in a Channel, -selecting users to add in a channel, etc. The `StreamUserListView` displays a list -of users. - -:::note -Make sure to check the [StreamUserListController](../stream_chat_flutter_core/stream_user_list_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamUserListView`. -::: - -### Basic Example - -```dart -class UserListPage extends StatefulWidget { - const UserListPage({Key? key}) : super(key: key); - - @override - State createState() => _UserListPageState(); -} - -class _UserListPageState extends State { - late final StreamUserListController _userListController = - StreamUserListController( - client: StreamChat.of(context).client, - limit: 25, - filter: Filter.and( - [Filter.notEqual('id', StreamChat.of(context).currentUser!.id)], - ), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - @override - Widget build(BuildContext context) { - return RefreshIndicator( - onRefresh: () => _userListController.refresh(), - child: StreamUserListView( - controller: _userListController, - ), - ); - } -} -``` - -### Customize The User Items - -You can use your own widget for the user items using the `itemBuilder` parameter. - -```dart -StreamUsersListView( - // ... - itemBuilder: (context, users, index, defaultWidget) { - return Text(user[index].name); - }, -), -``` - -### Selecting Users - -The `StreamUserListView` widget allows selecting users in a list. The `defaultWidget` returned can be customized to indicate that it has been selected. - -```dart -Set _selectedUsers = {}; - -StreamUserListView( - controller: _userListController, - itemBuilder: (context, users, index, defaultWidget) { - return defaultWidget.copyWith( - selected: _selectedUsers.contains(users[index]), - ); - }, - onUserTap: (user) { - setState(() { - _selectedUsers.add(user); - }); - }, -); -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/_category_.json b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/_category_.json deleted file mode 100644 index 8d738e8937..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Stream Chat Flutter Core", - "position": 4 -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/introduction.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/introduction.mdx deleted file mode 100644 index a59faf1017..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/introduction.mdx +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: introduction -title: Introduction ---- - -Understanding The Core Package Of The Flutter SDK - -This package provides business logic to fetch common things required for integrating Stream Chat into your application. -The core package allows more customisation and hence provides business logic but no UI components. -Please use the `stream_chat_flutter` package for the full fledged suite of UI components or `stream_chat` for the low-level client. - -### Background - -In the early days of the Flutter SDK, the SDK was only split into the LLC (`stream_chat`) and -the UI package (`stream_chat_flutter`). With this you could use a fully built interface with the UI package -or a fully custom interface with the LLC. However, we soon recognised the need for a third intermediary -package which made tasks like building and modifying a list of channels or messages easy but without -the complexity of using low level components. The Core package (`stream_chat_flutter_core`) is a manifestation -of the same idea and allows you to build an interface with Stream Chat without having to deal with -low level code and architecture as well as implementing your own theme and UI effortlessly. -Also, it has very few dependencies. - -We will now explore the components of this intermediary package and understand how it helps you build -the experience you want your users to have. - -The package primarily contains a bunch of controller classes. -Controllers are used to handle the business logic of the chat. You can use them together with our UI widgets, or you can even use them to build your own UI. - -* StreamChannelListController -* StreamUserListController -* StreamMessageSearchListController -* StreamMessageInputController -* LazyLoadScrollView -* PagedValueListenableBuilder - -This section goes into the individual core package widgets and their functional use. diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/lazy_load_scroll_view.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/lazy_load_scroll_view.mdx deleted file mode 100644 index a826da547e..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/lazy_load_scroll_view.mdx +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: lazy_load_scroll_view -title: LazyLoadScrollView ---- - -A Widget For Building A Paginated List - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/LazyLoadScrollView-class.html) - -### Background - -The `LazyLoadScrollView` is a widget that helps you build a paginated list. -It provides callbacks to notify you when the list has been scrolled to the bottom and when the list has been scrolled to the top and other necessary callbacks. - -#### Callbacks - -* onStartOfPage: called when the list has been scrolled to the top of the page. - -* onEndOfPage: called when the list has been scrolled to the bottom of the page. - -* onPageScrollStart: called when the scroll of the list starts. - -* onPageScrollEnd: called when the scroll of the list ends. - -* onInBetweenOfPage: called when the list is not either at the top nor at the bottom of the page. - -### Basic Example - -Building a paginated list is a very common task. Here is an example of how to use the `LazyLoadScrollView` to build a simple list with pagination. - -```dart -LazyLoadScrollView( - onEndOfPage: _paginateData, - /// The child could be any widget which dispatches [ScrollNotification]s. - /// For example [ListView], [GridView] or [CustomScrollView]. - child: ListView.builder( - itemBuilder: ((context, index) => _buildListTile), - ), -) -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/message_list_core.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/message_list_core.mdx deleted file mode 100644 index f8adf146e8..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/message_list_core.mdx +++ /dev/null @@ -1,71 +0,0 @@ ---- -id: message_list_core -title: MessageListCore ---- - -A Widget For Building A List Of Messages - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/MessageListCore-class.html) - -### Background - -The UI SDK of Stream Chat supplies a `MessageListView` class that builds a list of channels fetching -according to the filters and sort order given. However, in some cases, implementing novel UI is necessary -that cannot be done using the customization approaches given in the widget. - -To do this, we extracted the logic required for fetching channels into a 'Core' widget - a widget that -fetches channels in the expected way via the usual parameters but does not supply any UI and instead -exposes builders to build the UI in situations such as loading, empty data, errors, and on data received. - -### Basic Example - -`MessageListCore` is a simplified class that allows fetching a list of -messages while exposing UI builders. - -This allows you to construct your own UI while not having to -worry about the specific logic of fetching messages in a channel. - -A `MessageListController` is used to paginate data. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Column( - children: [ - Expanded( - child: MessageListCore( - emptyBuilder: (context) { - return Center( - child: Text('Nothing here...'), - ); - }, - loadingBuilder: (context) { - return Center( - child: CircularProgressIndicator(), - ); - }, - messageListBuilder: (context, list) { - return MessagesPage(list); - }, - errorWidgetBuilder: (context, err) { - return Center( - child: Text('Error'), - ); - }, - ), - ), - ], - ), - ); - } -} -``` - -Make sure to have a `StreamChannel` ancestor in order to provide the -information about the channels. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/paged_value_listenable_builder.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/paged_value_listenable_builder.mdx deleted file mode 100644 index e02a26cf99..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/paged_value_listenable_builder.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -id: paged_value_listenable_builder -title: PagedValueListenableBuilder ---- - -A Widget Whose Content Stays Synced With A `ValueNotifier` Of Type `PagedValue`. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/PagedValueListenableBuilder-class.html) - -### Background - -Given a `PagedValueNotifier` implementation and a [builder] which builds widgets from -concrete values of `PagedValue`, this class will automatically register itself as a -listener of the [PagedValueNotifier] and call the [builder] with updated values -when the value changes. - -### Basic Example - -```dart -class UserNameValueNotifier extends PagedValueNotifier { - UserNameValueNotifier() : super(const PagedValue.loading()); - - @override - Future doInitialLoad() async { - // Imitating network delay - await Future.delayed(const Duration(seconds: 1)); - value = const PagedValue( - items: ['Sahil', 'Salvatore', 'Reuben'], - - /// Passing the key to load the next page - nextPageKey: nextPageKey, - ); - } - - @override - Future loadMore(int nextPageKey) async { - // Imitating network delay - await Future.delayed(const Duration(seconds: 1)); - final previousItems = value.asSuccess.items; - final newItems = previousItems + ['Deven', 'Sacha', 'Gordon']; - value = PagedValue( - items: newItems, - // Passing nextPageKey as null to indicate - // that there are no more items. - nextPageKey: null, - ); - } -} - -class _MyHomePageState extends State { - final pagedValueNotifier = UserNameValueNotifier(); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Center( - child: PagedValueListenableBuilder( - builder: (context, value, child) { - // This builder will only get called when the _counter - // is updated. - return value.when( - (userNames, nextPageKey, error) => Column( - children: [ - const Text('Usernames:'), - Expanded( - child: ListView( - children: userNames.map((it) => Text(it)).toList(), - ), - ), - if (nextPageKey != null) - TextButton( - child: const Text('Load more'), - onPressed: () => pagedValueNotifier.loadMore(nextPageKey), - ), - ], - ), - loading: () => CircularProgressIndicator(), - error: (e) => Text('Error: $e'), - ); - }, - valueListenable: pagedValueNotifier, - ), - ), - ); - } -} -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/setup.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/setup.mdx deleted file mode 100644 index f297484274..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/setup.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -id: setup -title: Setup ---- - -Understanding Setup For `stream_chat_flutter_core` - -### Add pub.dev dependency - -First, you need to add the `stream_chat_flutter_core` dependency to your pubspec.yaml - -You can either run this command: - -```shell -flutter pub add stream_chat_flutter_core -``` - -OR - -Add this line in the dependencies section of your pubspec.yaml after substituting latest version: - -```yaml -dependencies: - stream_chat_flutter_core: ^latest_version -``` - -You can find the package details on [pub.dev](https://pub.dev/packages/stream_chat_flutter_core). diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_channel_list_controller.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_channel_list_controller.mdx deleted file mode 100644 index 71e223cbb9..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_channel_list_controller.mdx +++ /dev/null @@ -1,150 +0,0 @@ ---- -id: stream_channel_list_controller -title: StreamChannelListController ---- - -A Widget For Controlling A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamChannelListController-class.html) - -### Background - -The `StreamChannelListController` is a controller class that allows you to control a list of channels. -`StreamChannelListController` is a required parameter of the `StreamChannelListView` widget. -Check the [`StreamChannelListView` documentation](../stream_chat_flutter/stream_channel_list_view.mdx) to read more about that. - -The `StreamChannelListController` also listens for various events and manipulates the current list of channels accordingly. -Passing a `StreamChannelListEventHandler` to the `StreamChannelListController` will allow you to customize this behaviour. - -### Basic Example - -Building a custom channel list is a very common task. Here is an example of how to use the `StreamChannelListController` to build a simple list with pagination. - -First of all we should create an instance of the `StreamChannelListController` and provide it with the `StreamChatClient` instance. -You can also add a `Filter`, a list of `SortOption`s and other pagination-related parameters. - -```dart -class ChannelListPageState extends State { - /// Controller used for loading more data and controlling pagination in - /// [StreamChannelListController]. - late final channelListController = StreamChannelListController( - client: StreamChatCore.of(context).client, - filter: Filter.and([ - Filter.equal('type', 'messaging'), - Filter.in_( - 'members', - [ - StreamChatCore.of(context).currentUser!.id, - ], - ), - ]), - ); -``` - -Make sure you call `channelListController.doInitialLoad()` to load the initial data and `channelListController.dispose()` when the controller is no longer required. - -```dart -@override -void initState() { - channelListController.doInitialLoad(); - super.initState(); -} - -@override -void dispose() { - channelListController.dispose(); - super.dispose(); -} -``` - -The `StreamChannelListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of channels has changed. -You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest channels. - -```dart -@override -Widget build(BuildContext context) => Scaffold( - body: PagedValueListenableBuilder( - valueListenable: channelListController, - builder: (context, value, child) { - return value.when( - (channels, nextPageKey, error) => LazyLoadScrollView( - onEndOfPage: () async { - if (nextPageKey != null) { - channelListController.loadMore(nextPageKey); - } - }, - child: ListView.builder( - /// We're using the channels length when there are no more - /// pages to load and there are no errors with pagination. - /// In case we need to show a loading indicator or and error - /// tile we're increasing the count by 1. - itemCount: (nextPageKey != null || error != null) - ? channels.length + 1 - : channels.length, - itemBuilder: (BuildContext context, int index) { - if (index == channels.length) { - if (error != null) { - return TextButton( - onPressed: () { - channelListController.retry(); - }, - child: Text(error.message), - ); - } - return CircularProgressIndicator(); - } - - final _item = channels[index]; - return ListTile( - title: Text(_item.name ?? ''), - subtitle: StreamBuilder( - stream: _item.state!.lastMessageStream, - initialData: _item.state!.lastMessage, - builder: (context, snapshot) { - if (snapshot.hasData) { - return Text(snapshot.data!.text!); - } - - return const SizedBox(); - }, - ), - onTap: () { - /// Display a list of messages when the user taps on - /// an item. We can use [StreamChannel] to wrap our - /// [MessageScreen] screen with the selected channel. - /// - /// This allows us to use a built-in inherited widget - /// for accessing our `channel` later on. - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: _item, - child: const MessageScreen(), - ), - ), - ); - }, - ); - }, - ), - ), - loading: () => const Center( - child: SizedBox( - height: 100, - width: 100, - child: CircularProgressIndicator(), - ), - ), - error: (e) => Center( - child: Text( - 'Oh no, something went wrong. ' - 'Please check your config. $e', - ), - ), - ); - }, - ), - ); -``` - -In this case we're using the [`LazyLoadScrollView`](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_channel_list_event_handler.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_channel_list_event_handler.mdx deleted file mode 100644 index 395a4c1fb8..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_channel_list_event_handler.mdx +++ /dev/null @@ -1,63 +0,0 @@ ---- -id: stream_channel_list_event_handler -title: StreamChannelListEventHandler ---- - -A Class To Customize The Event Handler For The StreamChannelListController. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamChannelListEventHandler-class.html) - -### Background - -A `StreamChannelListEventHandler` is a class that handles the events that are related to the channel list loaded by `StreamChannelListController`. -The `StreamChannelListController` automatically creates a `StreamChannelListEventHandler` internally and handles the events. In order to provide a custom -implementation of `StreamChannelListEventHandler`, you need to create a class that extends the `StreamChannelListEventHandler` class. - -### Basic Example - -There are 2 ways to provide a custom implementation of `StreamChannelListEventHandler`: - -* Create a class that extends the `StreamChannelListEventHandler` and pass it down to the controller. - -```dart -class MyCustomEventHandler extends StreamChannelListEventHandler { - @override - void onConnectionRecovered( - Event event, - StreamChannelListController controller, - ) { - // Write your own custom implementation here - } -} -``` - -Pass it down to the controller: - -```dart - late final listController = StreamChannelListController( - client: StreamChat.of(context).client, - eventHandler: MyCustomEventHandler(), - ); -``` - -* Mix the `StreamChannelListEventHandler` into your widget state. - -```dart -class _ChannelListPageState extends State - with StreamChannelListEventHandler { - - @override - void onConnectionRecovered( - Event event, - StreamChannelListController controller, - ) { - // Write your own custom implementation here - } - - late final _listController = StreamChannelListController( - client: StreamChat.of(context).client, - eventHandler: this, - ); -} -``` - diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_chat_core.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_chat_core.mdx deleted file mode 100644 index ded66b22f6..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_chat_core.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -id: stream_chat_core -title: StreamChatCore ---- - -`StreamChatCore` is a version of `StreamChat` found in `stream_chat_flutter` that is decoupled from -theme and initialisations. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamChatCore-class.html) - -`StreamChatCore` is used to provide information about the chat client to the widget tree. -This Widget is used to react to life cycle changes and system updates. -When the app goes into the background, the web socket connection is automatically closed and when it goes back to foreground the connection is opened again. - -Like the `StreamChat` widget in the higher level UI package, the `StreamChatCore` widget should -be on the top level before using any Stream functionality: - -```dart -return MaterialApp( - title: 'Stream Chat Core Example', - home: HomeScreen(), - builder: (context, child) => StreamChatCore( - client: client, - child: child!, - ), - ); -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_message_input_controller.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_message_input_controller.mdx deleted file mode 100644 index a1c85842a9..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_message_input_controller.mdx +++ /dev/null @@ -1,88 +0,0 @@ ---- -id: stream_message_input_controller -title: StreamMessageInputController ---- - -A Widget For Controlling A Message Input - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamMessageInputController-class.html) - -### Background - -The `StreamMessageInputController` is a controller class that embed the business logic to compose a message. -`StreamMessageInputController` is a parameter of the `StreamMessageInput` widget. -Check the [`StreamMessageInput` documentation](../stream_chat_flutter/stream_message_input.mdx) to read more about that. - -### Basic Example - -Building a custom message input is a common task. Here is an example of how to use the `StreamMessageInputController` to build a simple custom message input widget. - -First of all we should create an instance of the `StreamMessageInputController`. - -```dart -class MessageScreenState extends State { - final StreamMessageInputController messageInputController = StreamMessageInputController(); -``` - -Make sure you call `messageInputController.dispose()` when the controller is no longer required. - -```dart -@override -void dispose() { - messageInputController.dispose(); - super.dispose(); -} -``` - -The `StreamMessageInputController` is basically a `ValueNotifier` that notifies you when the message being composed has changed. -You can use a `ValueListenableBuilder` to build your UI depending on the latest message. -For a very simple message input you could even pass the `messageInputController.textEditingController` to your `TextField` and set the `onChanged` callback. - -```dart -... -Padding( - padding: const EdgeInsets.all(8), - child: Row( - children: [ - Expanded( - child: TextField( - controller: messageInputController.textEditingController, - onChanged: (s) => messageInputController.text = s, - decoration: const InputDecoration( - hintText: 'Enter your message', - ), - ), - ), - Material( - type: MaterialType.circle, - color: Colors.blue, - clipBehavior: Clip.hardEdge, - child: InkWell( - onTap: () async { - if (messageInputController.message.text?.isNotEmpty == - true) { - await channel.sendMessage( - messageInputController.message, - ); - messageInputController.clear(); - if (mounted) { - _updateList(); - } - } - }, - child: const Padding( - padding: EdgeInsets.all(8), - child: Center( - child: Icon( - Icons.send, - color: Colors.white, - ), - ), - ), - ), - ), - ], - ), -), -... -``` diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_message_search_list_controller.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_message_search_list_controller.mdx deleted file mode 100644 index 9762876ed1..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_message_search_list_controller.mdx +++ /dev/null @@ -1,127 +0,0 @@ ---- -id: stream_message_search_list_controller -title: StreamMessageSearchListController ---- - -A Widget For Controlling A List Of Searched Messages - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamMessageSearchListController-class.html) - -### Background - -The `StreamMessageSearchListController` is a controller class that allows you to control a list of searched messages. -`StreamMessageSearchListController` is a required parameter of the `StreamMessageSearchListView` widget. -Check the [`StreamMessageSearchListView` documentation](../stream_chat_flutter/stream_message_search_list_view.mdx) to read more about that. - -### Basic Example - -Building a custom message search feature is a common task. Here is an example of how to use the `StreamMessageSearchListController` to build a simple search list with pagination. - -First of all we should create an instance of the `StreamMessageSearchListController` and provide it with the `StreamChatClient` instance. -You can also add a `Filter`, a list of `SortOption`s and other pagination-related parameters. - -```dart -class SearchListPageState extends State { - /// Controller used for loading more data and controlling pagination in - /// [StreamMessageSearchListController]. - late final messageSearchListController = StreamMessageSearchListController( - client: StreamChatCore.of(context).client, - ); -``` - -Make sure you call `messageSearchListController.doInitialLoad()` to load the initial data and `messageSearchListController.dispose()` when the controller is no longer required. - -```dart -@override -void initState() { - messageSearchListController.doInitialLoad(); - super.initState(); -} - -@override -void dispose() { - messageSearchListController.dispose(); - super.dispose(); -} -``` - -The `StreamMessageSearchListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of responses has changed. -You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest responses. - -```dart -@override -Widget build(BuildContext context) => Scaffold( - body: Column( - children: [ - TextField( - /// This is just a sample implementation of a search field. - /// In a real-world app you should throttle the search requests. - /// You can use our library [rate_limiter](https://pub.dev/packages/rate_limiter). - onChanged: (s) { - messageSearchListController.searchQuery = s; - messageSearchListController.doInitialLoad(); - }, - ), - Expanded( - child: PagedValueListenableBuilder( - valueListenable: messageSearchListController, - builder: (context, value, child) { - return value.when( - (responses, nextPageKey, error) => LazyLoadScrollView( - onEndOfPage: () async { - if (nextPageKey != null) { - messageSearchListController.loadMore(nextPageKey); - } - }, - child: ListView.builder( - /// We're using the responses length when there are no more - /// pages to load and there are no errors with pagination. - /// In case we need to show a loading indicator or and error - /// tile we're increasing the count by 1. - itemCount: (nextPageKey != null || error != null) - ? responses.length + 1 - : responses.length, - itemBuilder: (BuildContext context, int index) { - if (index == responses.length) { - if (error != null) { - return TextButton( - onPressed: () { - messageSearchListController.retry(); - }, - child: Text(error.message), - ); - } - return CircularProgressIndicator(); - } - - final _item = responses[index]; - return ListTile( - title: Text(_item.channel?.name ?? ''), - subtitle: Text(_item.message.text ?? ''), - ); - }, - ), - ), - loading: () => const Center( - child: SizedBox( - height: 100, - width: 100, - child: CircularProgressIndicator(), - ), - ), - error: (e) => Center( - child: Text( - 'Oh no, something went wrong. ' - 'Please check your config. $e', - ), - ), - ); - }, - ), - ), - ], - ), - ); -``` - -In this case we're using the [`LazyLoadScrollView`](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_user_list_controller.mdx b/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_user_list_controller.mdx deleted file mode 100644 index 4b584c89f4..0000000000 --- a/docusaurus/flutter_versioned_docs/version-4.x.x/Flutter/stream_chat_flutter_core/stream_user_list_controller.mdx +++ /dev/null @@ -1,111 +0,0 @@ ---- -id: stream_user_list_controller -title: StreamUserListController ---- - -A Widget For Controlling A List Of Users - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamUserListController-class.html) - -### Background - -The `StreamUserListController` is a controller class that allows you to control a list of users. -`StreamUserListController` is a required parameter of the `StreamUserListView` widget. -Check the [`StreamUserListView` documentation](../stream_chat_flutter/stream_user_list_view.mdx) to read more about that. - -### Basic Example - -Building a custom user list is a very common task. Here is an example of how to use the `StreamUserListController` to build a simple list with pagination. - -First of all we should create an instance of the `StreamUserListController` and provide it with the `StreamChatClient` instance. -You can also add a `Filter`, a list of `SortOption`s and other pagination-related parameters. - -```dart -class UserListPageState extends State { - /// Controller used for loading more data and controlling pagination in - /// [StreamUserListController]. - late final userListController = StreamUserListController( - client: StreamChatCore.of(context).client, - ); -``` - -Make sure you call `userListController.doInitialLoad()` to load the initial data and `userListController.dispose()` when the controller is no longer required. - -```dart -@override -void initState() { - userListController.doInitialLoad(); - super.initState(); -} - -@override -void dispose() { - userListController.dispose(); - super.dispose(); -} -``` - -The `StreamUserListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of users has changed. -You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest users. - -```dart -@override -Widget build(BuildContext context) => Scaffold( - body: PagedValueListenableBuilder( - valueListenable: userListController, - builder: (context, value, child) { - return value.when( - (users, nextPageKey, error) => LazyLoadScrollView( - onEndOfPage: () async { - if (nextPageKey != null) { - userListController.loadMore(nextPageKey); - } - }, - child: ListView.builder( - /// We're using the users length when there are no more - /// pages to load and there are no errors with pagination. - /// In case we need to show a loading indicator or and error - /// tile we're increasing the count by 1. - itemCount: (nextPageKey != null || error != null) - ? users.length + 1 - : users.length, - itemBuilder: (BuildContext context, int index) { - if (index == users.length) { - if (error != null) { - return TextButton( - onPressed: () { - userListController.retry(); - }, - child: Text(error.message), - ); - } - return CircularProgressIndicator(); - } - - final _item = users[index]; - return ListTile( - title: Text(_item.name ?? ''), - ); - }, - ), - ), - loading: () => const Center( - child: SizedBox( - height: 100, - width: 100, - child: CircularProgressIndicator(), - ), - ), - error: (e) => Center( - child: Text( - 'Oh no, something went wrong. ' - 'Please check your config. $e', - ), - ), - ); - }, - ), - ); -``` - -In this case we're using the [`LazyLoadScrollView`](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/01-basics/_category_.json b/docusaurus/flutter_versioned_docs/version-5.x.x/01-basics/_category_.json deleted file mode 100644 index 69a9460db5..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/01-basics/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Basics" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/01-basics/choose_package.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/01-basics/choose_package.mdx deleted file mode 100644 index ff8230f101..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/01-basics/choose_package.mdx +++ /dev/null @@ -1,56 +0,0 @@ ---- -id: choose_package -title: Choosing The Right SDK ---- - -Choosing The Right Flutter Package - -### Why the SDK is split into different packages - -Different applications need different levels of customization and integration with the Stream Chat SDK. -To do this, the Flutter SDK is split into three different packages which build upon the last and give -varying levels of control to the developer. The higher level packages offer better compatibility out of the -box while the lower level SDKs offer fine grained control. There is also a separate package for persistence -which allows you persist data locally which works with all packages. - -### How do I choose? - -#### The case for `stream_chat_flutter` - -For the quickest way to integrate Stream Chat with your app, the UI SDK (`stream_chat_flutter`) is the -way to go. `stream_chat_flutter` contains prebuilt components that manage most operations like data -fetching, pagination, sending a message, and more. This ensures you have a nearly out-of-the-box -experience adding chat to your applications. It is also possible to use this in conjunction with -lower level operations of the SDK to get the best of both worlds. - -:::note -The package allows customization of components to a large extent making it easy to tweak the theme -to match your app colors and such. If you require any additional feature or customization, feel free -to request this through our support channels. -::: - -Summary: - -For the quickest and easiest way to add Chat to your app with prebuilt UI components, use `stream_chat_flutter` - - -#### The case for `stream_chat_flutter_core` - -If your application involves UI that does not fit in with the `stream_chat_flutter` components, `stream_chat_flutter_core` -strips away the UI associated with the components and provides the data fetching and manipulation -capabilities while supplying builders for UI. This allows you to implement your own UI and themes -completely independently while not worrying about writing functions for data and pagination. - -Summary: - -For implementing your own custom UI while not having to worry about lower level API calls, use `stream_chat_flutter_core`. - -#### The case for `stream_chat` - -The `stream_chat` package is the Low-level Client (LLC) of Stream Chat in Flutter. This package wraps -the underlying functionality of Stream Chat and allows the most customization in terms of UI, data, -and architecture. - -Summary: - -For the most control over the SDK and dealing with low level calls to the API, use `stream_chat`. diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/01-basics/introduction.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/01-basics/introduction.mdx deleted file mode 100644 index a618bbeb21..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/01-basics/introduction.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -slug: / -id: introduction -title: Overview ---- -About The Flutter SDK - -![](../assets/sdk_title.png) - -Stream Chat is a service that helps you easily build a full chat experience in your Flutter apps. -We also support a variety of other SDKs. - -This section of the documentation focuses on our Flutter SDK which helps you easily -ship high quality messaging experiences in apps and programs built with the [Flutter toolkit -made by Google](https://flutter.dev). - -The Stream Chat Flutter SDK comprises five different packages to choose from, ranging from ones -giving you complete control to ones that give you a rich out-of-the-box chat experience. - -The packages that make up the Stream Chat SDK are: - -1. Low Level Client (`stream_chat`): a pure Dart package that can be used on any Dart project. -It provides a low-level client to access the Stream Chat service. -2. Core (`stream_chat_flutter_core`): provides business logic to fetch common things required -for integrating Stream Chat into your application. -The core package allows more customisation and hence provides business logic but no UI components. -3. UI (`stream_chat_flutter`): this library includes both a low-level chat SDK and a set of -reusable and customizable UI components. -4. Persistence (`stream_chat_persistence`): provides a persistence client for fetching and -saving chat data locally. -5. Localizations (`stream_chat_localizations`): provides a set of localizations for the SDK. - -We recommend building prototypes using the full UI package, [`stream_chat_flutter`](https://pub.dev/packages/stream_chat_flutter), -since it contains UI widgets already integrated with Stream's API. It is the fastest way to get up -and running using Stream chat in your app. - -The Flutter SDK enables you to build any type of chat or messaging experience for Android, iOS, Web -and Desktop. - -If you're building a very custom UI and would prefer a more lean package, -[`stream_chat_flutter_core`](https://pub.dev/packages/stream_chat_flutter_core) will be suited to this -use case. Core allows you to build custom, expressive UIs while retaining the benefits of our full -Flutter SDK. APIs for accessing and controlling users, sending messages, and so forth are seamlessly integrated -into this package and accessible via providers and builders. - -Before going into the docs, let's take a small detour to look at how the elements of Stream Chat are structured. - -### Basic Structure - -There are two core elements in chat, Users and Channels. -Channels are groups of one or more users that can message each other. -In an app, you need to have a user connected to query channels. - -There is no specific distinction between a chat with only two people and a group chat, -but there is a way to create a unique chat between a certain number of people by creating a distinct channel. - -![](../assets/chat_basics.png) - -In essence, a normal two-person chat would be a distinct channel created with two members (you cannot add or delete members in this channel), whereas a group created with two people would simply be a non distinct channel (possible to add or remove members). - -:::note -It is also possible to add more than two people in a distinct channel which retains the same add/removal properties and resembles the Slack DMs where you can DM one or more people as well. -::: - -In summary, if you were creating a Whatsapp-like app, the first screen would be a list of channels - which on opening would show a list of messages that were sent by the users in the Channel. - -While this is a simplistic overview of the service, the Flutter SDK handles the UI and more time consuming things (media upload, offline storage, theming, etc.) for you. - -Before reading the docs, consider trying our [online API tour](https://getstream.io/chat/get_started/), -it is a nice way to learn how the API works. -It's in-browser so you'll need to use JavaScript but the core concepts are pretty much the same as Dart. - -You may also like to look at the [Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) -which focuses on using the UI package to get Stream Chat integrated into a Flutter app. - -Further sections break down each individual packages and explain several common operations. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/01-basics/versioning_policy.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/01-basics/versioning_policy.mdx deleted file mode 100644 index 9f50c98f9e..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/01-basics/versioning_policy.mdx +++ /dev/null @@ -1,19 +0,0 @@ ---- -id: versioning_policy -title: Versioning Policy ---- - -All of the Stream Chat packages follow [semantic versioning](https://semver.org/). - -That means that with a version number x.y.z (major.minor.patch): -- When releasing bug fixes (backwards compatible), we make a patch release by changing the z number (ex: 3.6.2 to 3.6.3). A bug fix is defined as an internal change that fixes incorrect behavior. -- When releasing new features or non-critical fixes, we make a minor release by changing the y number (ex: 3.6.2 to 3.7.0). -- When releasing breaking changes (backward incompatible), we make a major release by changing the x number (ex: 3.6.2 to 4.0.0). - -See the [semantic versioning](https://dart.dev/tools/pub/versioning#semantic-versions) section from the Dart docs for more information. - -This versioning policy does not apply to prerelease packages (below major version of 1). See this -[StackOverflow thread](https://stackoverflow.com/questions/66201337/how-do-dart-package-versions-work-how-should-i-version-my-flutter-plugins) -for more information on Dart package versioning. - -Whenever possible, we will add deprecation warnings in preparation for future breaking changes. diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/01-customize_message_widget.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/01-customize_message_widget.mdx deleted file mode 100644 index 405de137ab..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/01-customize_message_widget.mdx +++ /dev/null @@ -1,185 +0,0 @@ ---- -id: customize_message_widget -title: Message ---- - -Customizing Text Messages with the StreamMessageWidget - -### Introduction - -Every application provides a unique look and feel to their own messaging interface including and not -limited to fonts, colors, and shapes. - -This guide details how to customize the `StreamMessageWidget` in the Stream Chat Flutter UI SDK. - -### Building Custom Messages - -This guide goes into detail about the ability to customize the `StreamMessageWidget`. However, if you want -to customize the default `StreamMessageWidget` in the `StreamMessageListView` provided, you can use the `.copyWith()` method -provided inside the `messageBuilder` parameter of the `StreamMessageListView` like this: - -```dart -StreamMessageListView( - messageBuilder: (context, details, messageList, defaultImpl) { - return defaultImpl.copyWith( - ... - ); - }, -), -``` - -### Theming - -You can customize the `StreamMessageWidget` using the `StreamChatTheme` class, so that you can change the -message theme at the top instead of creating your own `StreamMessageWidget` at the lower implementation level. - -There are several things you can change in the theme including text styles and colors of various elements. - -You can also set a different theme for the user's own messages and messages received by them. - -:::note -Theming allows you to change minor factors like style while using the widget directly allows you much -more customization such as replacing a certain widget with another. Some things can only be customized -through the widget and not the theme. -::: - -Here is an example: - -```dart -StreamChatThemeData( - - /// Sets theme for user's messages - ownMessageTheme: StreamMessageThemeData( - messageBackgroundColor: colorTheme.textHighEmphasis, - ), - - /// Sets theme for received messages - otherMessageTheme: StreamMessageThemeData( - avatarTheme: StreamAvatarThemeData( - borderRadius: BorderRadius.circular(8), - ), - ), - -) -``` - -![](../../assets/message_theming.png) - -#### Change message text style - -The `StreamMessageWidget` has multiple `Text` widgets that you can manipulate the styles of. The three main -are the actual message text, user name, message links, and the message timestamp. - -```dart -StreamMessageThemeData( - messageTextStyle: TextStyle(...), - createdAtStyle: TextStyle(...), - messageAuthorStyle: TextStyle(...), - messageLinksStyle: TextStyle(...), -) -``` - -![](../../assets/message_styles.png) - -#### Change avatar theme - -You can change the attributes of the avatar (if displayed) using the `avatarTheme` property. - -```dart -StreamMessageThemeData( - avatarTheme: StreamAvatarThemeData( - borderRadius: BorderRadius.circular(8), - ), -) -``` - -![](../../assets/message_rounded_avatar.png) - -#### Changing Reaction theme - -You also customize the reactions attached to every message using the theme. - -```dart -StreamMessageThemeData( - reactionsBackgroundColor: Colors.red, - reactionsBorderColor: Colors.redAccent, - reactionsMaskColor: Colors.pink, -), -``` - -![](../../assets/message_reaction_theming.png) - -### Changing Message Actions - -When a message is long pressed, the `StreamMessageActionsModal` is shown. - -The `StreamMessageWidget` allows showing or hiding some options if you so choose. - -```dart -StreamMessageWidget( - ... - showUsername = true, - showTimestamp = true, - showReactions = true, - showDeleteMessage = true, - showEditMessage = true, - showReplyMessage = true, - showThreadReplyMessage = true, - showResendMessage = true, - showCopyMessage = true, - showFlagButton = true, - showPinButton = true, - showPinHighlight = true, -), -``` - -![](../../assets/message_widget_actions.png) - -### Building attachments - -The `customAttachmentBuilders` property allows you to build any kind of attachment (inbuilt or custom) -in your own way. While a separate guide is written for this, it is included here because of relevance. - -```dart -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - customAttachmentBuilders: { - 'location': (context, message, attachments) { - final attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'], - attachments[0].extraData['longitude'], - ), - ); - - return WrapAttachmentWidget( - attachmentWidget: attachmentWidget, - attachmentShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - ); - } - }, - ); - }, -), -``` - -### Widget Builders - -Some parameters allow you to construct your own widget in place of some elements in the `StreamMessageWidget`. - -These are: -* `userAvatarBuilder` : Allows user to substitute their own widget in place of the user avatar. -* `editMessageInputBuilder` : Allows user to substitute their own widget in place of the input in edit mode. -* `textBuilder` : Allows user to substitute their own widget in place of the text. -* `bottomRowBuilder` : Allows user to substitute their own widget in the bottom of the message when not deleted. -* `deletedBottomRowBuilder` : Allows user to substitute their own widget in the bottom of the message when deleted. - -```dart -StreamMessageWidget( - ... - textBuilder: (context, message) { - // Add your own text implementation here. - }, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/02-customize_text_messages.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/02-customize_text_messages.mdx deleted file mode 100644 index da6071843f..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/02-customize_text_messages.mdx +++ /dev/null @@ -1,162 +0,0 @@ ---- -id: customize_text_messages -title: Message List View ---- - -Customizing Text Messages - -### Introduction - -Every application provides a unique look and feel to their own messaging interface including and not -limited to fonts, colors, and shapes. - -This guide details how to customize message text in the `StreamMessageListView` / `StreamMessageWidget` in the -Stream Chat Flutter UI SDK. - -:::note -This guide is specifically for the `StreamMessageListView` but if you intend to display a `StreamMessageWidget` -separately, follow the same process without the `.copyWith` and use the default constructor instead. -::: - -### Basics of customizing a `StreamMessageWidget` - -First, add a `StreamMessageListView` in the appropriate place where you intend to display messages from a -channel. - -```dart -StreamMessageListView( - ... -) -``` - -Now, we use the `messageBuilder` parameter to build a custom message. The builder function also provides -the default implementation of the `StreamMessageWidget` so that we can change certain aspects of the widget -without redoing all of the default parameters. - -:::note -In earlier versions of the SDK, some `StreamMessageWidget` parameters were exposed directly through the `StreamMessageListView`, -however, this quickly becomes hard to maintain as more parameters and customizations are added to the -`StreamMessageWidget`. Newer version utilise a cleaner interface to change the parameters by supplying a -default message implementation as aforementioned. -::: - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget; - }, -) -``` - -We use `.copyWith()` to customize the widget: - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - ... - ); - }, -) -``` - -### Customizing text - -If you intend to simply change the theme for the text, you need not recreate the whole widget. The -`StreamMessageWidget` has a `messageTheme` parameter that allows you to pass the theme for most aspects -of the message. - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - messageTheme: StreamMessageThemeData( - ... - messageTextStyle: TextStyle(), - ), - ); - }, -) -``` - -If you want to replace the entire text widget in the `StreamMessageWidget`, you can use the `textBuilder` -parameter which provides a builder for creating a widget to substitute the default text.parameter - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - textBuilder: (context, message) { - return Text(message.text ?? ''); - }, - ); - }, -) -``` - -### Adding Hashtags - -To add elements like hashtags, we can override the `textBuilder` in the StreamMessageWidget: - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - textBuilder: (context, message) { - final text = _replaceHashtags(message.text)?.replaceAll('\n', '\\\n'); - final messageTheme = StreamChatTheme.of(context).ownMessageTheme; - - if (text == null) return const SizedBox(); - - return MarkdownBody( - data: text, - onTapLink: ( - String link, - String? href, - String title, - ) { - // Do something with tapped hashtag - }, - styleSheet: MarkdownStyleSheet.fromTheme( - Theme.of(context).copyWith( - textTheme: Theme.of(context).textTheme.apply( - bodyColor: messageTheme.messageTextStyle?.color, - decoration: messageTheme.messageTextStyle?.decoration, - decorationColor: messageTheme.messageTextStyle?.decorationColor, - decorationStyle: messageTheme.messageTextStyle?.decorationStyle, - fontFamily: messageTheme.messageTextStyle?.fontFamily, - ), - ), - ).copyWith( - a: messageTheme.messageLinksStyle, - p: messageTheme.messageTextStyle, - ), - ); - }, - ); - }, -) - -String? _replaceHashtags(String? text) { - if (text == null) return null; - - final exp = RegExp(r"\B#\w\w+"); - String result = text; - exp.allMatches(text).forEach((match){ - text = text!.replaceAll( - '${match.group(0)}', '[${match.group(0)}](${match.group(0)?.replaceAll(' ', '')})'); - }); - return result; -} -``` - -We can replace the hashtags using RegEx and add links for the MarkdownBody which is done here in the -`_replaceHashtags()` function. -Inside the textBuilder, we use the `flutter_markdown` package to build our hashtags as links. - -![](../../assets/hashtag_example.jpg) diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/03-customize_message_actions.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/03-customize_message_actions.mdx deleted file mode 100644 index b329f7648c..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/03-customize_message_actions.mdx +++ /dev/null @@ -1,81 +0,0 @@ ---- -id: customize_message_actions -title: Message Actions ---- - -Customizing Message Actions - -### Introduction - -Message actions pop up in message overlay, when you long-press a message. - -![](../../assets/message_actions.jpg) - -We have provided granular control over these actions. - -By default we render the following message actions: - -* edit message - -* delete message - -* reply - -* thread reply - -* copy message - -* flag message - -* pin message - -:::note -Edit and delete message are only available on messages sent by the user. -Additionally, pinning a message requires you to add the roles which are allowed to pin messages. -::: - -### Partially remove some message actions - -For example, if you only want to keep "copy message" and "delete message": -here is how to do it using the `messageBuilder` with our `StreamMessageWidget`. - -```dart -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - showFlagButton: false, - showEditMessage: false, - showCopyMessage: true, - showDeleteMessage: details.isMyMessage, - showReplyMessage: false, - showThreadReplyMessage: false, - ); - }, -) -``` - -### Add a new custom message action - -The SDK also allows you to add new actions into the dialog. - -For example, let's suppose you want to introduce a new message action - "Demo Action": - -We use the `customActions` parameter of the `StreamMessageWidget` to add extra actions. - -```dart -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - customActions: [ - StreamMessageAction( - leading: const Icon(Icons.add), - title: const Text('Demo Action'), - onTap: (message) { - /// Complete action here - }, - ), - ], - ); - }, -) -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/04-adding_custom_attachments.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/04-adding_custom_attachments.mdx deleted file mode 100644 index 2954523b75..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/04-adding_custom_attachments.mdx +++ /dev/null @@ -1,269 +0,0 @@ ---- -id: adding_custom_attachments -title: Attachments ---- - -Adding Your Own Types Of Attachments To A Message - -### Introduction - -Stream Chat supports attachment types like images, video and files by default. You can also add your -own types of attachments through the SDK such as location, audio, etc. - -This involves doing three things: - -1) Rendering the attachment thumbnail in the `StreamMessageInput` - -2) Sending a message with the custom attachment - -3) Rendering the custom message attachment - -To do this, let's check out an example to add location sharing to Stream Chat. - -### Location Sharing - -Let's build an example of location sharing option in the app: - -![](../../assets/location_sharing_example.jpg) - -* Show a "Share Location" button next to StreamMessageInput `Textfield`. - -* When the user presses this button, it should fetch the current location coordinates of the user, and send a message on the channel as follows: - -```dart -Message( - text: 'This is my location', - attachments: [ - Attachment( - uploadState: const UploadState.success(), - type: 'location', - extraData: const { - 'latitude': 'fetched_latitude', - 'longitude': 'fetched_longitude', - }, - ), - ], -) -``` - -For our example, we are going to use [`geolocator`](https://pub.dev/packages/geolocator) library. -Please check their [setup instructions](https://pub.dev/packages/geolocator) on their docs. - -NOTE: If you are testing on iOS simulator, you will need to set some dummy coordinates, as mentioned [here](https://stackoverflow.com/a/31238119/7489541). -Also don't forget to enable "location update" capability in background mode, from XCode. - -On the receiver end, `location` type attachment should be rendered in map view, in the `StreamMessageListView`. -We are going to use [Google Static Maps API](https://developers.google.com/maps/documentation/maps-static/overview) to render the map in the message. -You can use other libraries as well such as [`google_maps_flutter`](https://pub.dev/packages/google_maps_flutter). - -First, we add a button which when clicked fetches and shares location into the `MessageInput`: - -```dart -StreamMessageInput( - actions: [ - InkWell( - child: const Icon( - Icons.location_on, - size: 20, - color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, - ), - onTap: () { - final channel = StreamChannel.of(context).channel; - - _determinePosition().then((value) { - channel.sendMessage( - Message( - text: 'This is my location', - attachments: [ - Attachment( - uploadState: const UploadState.success(), - type: 'location', - extraData: { - 'latitude': value.latitude.toString(), - 'longitude': value.longitude.toString(), - }, - ), - ], - ), - ); - }).catchError((err) { - print('Error getting location!'); - }); - }, - ), - ], -), - -Future _determinePosition() async { - bool serviceEnabled; - LocationPermission permission; - - serviceEnabled = await Geolocator.isLocationServiceEnabled(); - if (!serviceEnabled) { - return Future.error('Location services are disabled.'); - } - - permission = await Geolocator.checkPermission(); - if (permission == LocationPermission.denied) { - permission = await Geolocator.requestPermission(); - if (permission == LocationPermission.deniedForever) { - return Future.error( - 'Location permissions are permanently denied, we cannot request permissions.'); - } - - if (permission == LocationPermission.denied) { - return Future.error( - 'Location permissions are denied'); - } - } - - return await Geolocator.getCurrentPosition(); -} -``` - -Next, we build the Static Maps URL (Add your API key before using the code snippet): - -```dart - String _buildMapAttachment(String lat, String long) { - final url = Uri( - scheme: 'https', - host: 'maps.googleapis.com', - port: 443, - path: '/maps/api/staticmap', - queryParameters: { - 'center': '${lat},${long}', - 'zoom': '15', - 'size': '600x300', - 'maptype': 'roadmap', - 'key': 'YOUR_API_KEY', - 'markers': 'color:red|${lat},${long}' - }); - - return url.toString(); - } -``` - -And then modify the `StreamMessageListView` and tell it how to build a location attachment, using the `messageBuilder` property and copying the default message implementation overriding the `customAttachmentBuilders` property: - -```dart -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - customAttachmentBuilders: { - 'location': (context, message, attachments) { - final attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'].toString(), - attachments[0].extraData['longitude'].toString(), - ), - ); - - return WrapAttachmentWidget( - attachmentWidget: attachmentWidget, - attachmentShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - ); - } - }, - ); - }, -), -``` - -This gives us the final location attachment: - -![](../../assets/location_sharing_example_message.jpg) - -Additionally, you can also add a thumbnail if a message has a location attachment (unlike in this case, where we sent the message directly). - -To do this, we will: - -1) Add an attachment instead of sending a message - -2) Customize the `StreamMessageInput` - -First, we add the attachment when the location button is clicked: - -```dart - StreamMessageInputController _messageInputController = StreamMessageInputController(); - - StreamMessageInput( - messageInputController: _messageInputController, - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20, - color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, - ), - onTap: () { - _determinePosition().then((value) { - _messageInputController.addAttachment( - Attachment( - uploadState: const UploadState.success(), - type: 'location', - extraData: { - 'latitude': value.latitude.toString(), - 'longitude': value.longitude.toString(), - }, - ), - ); - }).catchError((err) { - print('Error getting location!'); - }); - }, - ), - ], - ), -``` - -After this, we can build the thumbnail: - -```dart -StreamMessageInput( - messageInputController: _messageInputController, - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20, - color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, - ), - onTap: () { - _determinePosition().then((value) { - _messageInputController.addAttachment( - Attachment( - uploadState: const UploadState.success(), - type: 'location', - extraData: { - 'latitude': value.latitude.toString(), - 'longitude': value.longitude.toString(), - }, - ), - ); - }).catchError((err) { - print('Error getting location!'); - }); - }, - ), - ], - mediaAttachmentBuilder: ( - BuildContext context, - Attachment attachment, - ValueSetter? onRemovePressed, - ) { - if (attachment.type == 'location') { - return Image.network( - _buildMapAttachment( - attachment.extraData['latitude'].toString(), - attachment.extraData['longitude'].toString(), - ), - ); - } - return const SizedBox(); - }, -), -``` - -And we can see the thumbnails in the StreamMessageInput: - -![](../../assets/location_sharing_example_message_thumbnail.jpg) diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/05-customize_attachment_picker_modal.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/05-customize_attachment_picker_modal.mdx deleted file mode 100644 index 4e89830b50..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/05-customize_attachment_picker_modal.mdx +++ /dev/null @@ -1,167 +0,0 @@ ---- -id: customize_attachment_picker_modal -title: Attachment Picker Modal ---- - -Customizing the Attachment Picker Modal - -### Introduction - -The Attachment Picker is a modal that allows users to select attachments from their device. -It is generally used when a user taps the attachment button in the [StreamMessageInput](../../03-stream_chat_flutter/stream_message_input.mdx). - -By default, the Attachment Picker provides multiple picker options as per the platform. -- For example, on Mobile, the default options are Camera, Gallery, File, and Video. -- On Web and Desktop, the default options are Image, Video and File. - -### Customizing the Attachment Picker Modal - -The Attachment Picker Modal can be customized by passing the different values to the `showStreamAttachmentPickerModalBottomSheet` function. - -#### Initial Attachments - -The initial attachments can be passed to the Attachment Picker Modal in two ways. - - * By passing the `initialAttachments` parameter. - - ```dart - StreamMessageInputController _messageInputController = - StreamMessageInputController(); - ... - showStreamAttachmentPickerModalBottomSheet( - context: context, - initialAttachments: [ - // Pass the initial attachments to the modal here if any are available already (optional) - ..._messageInputController.attachments, - ], - ); - ``` - - * By creating a new instance of the `AttachmentPickerModalController` and passing it to the `controller` parameter. - - ```dart - final attachmentPickerController = StreamAttachmentPickerController( - initialAttachments: [ - // Pass the initial attachments to the modal here if any are available already (optional) - ...messageInputController.attachments, - ], - - // The `maxAttachmentSize` and `maxAttachmentCount` can also be set while creating a controller. - maxAttachmentSize: 10 * 1024 * 1024, // 10 MB - maxAttachmentCount: 10, // 10 attachments - ); - - showStreamAttachmentPickerModalBottomSheet( - context: context, - controller: attachmentPickerController, - ); - ``` - -#### Custom Attachment Picker Options - -The Attachment Picker Modal provides a default set of options as per the platform. -However, you can also customize the options by passing the `customOptions` parameter. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - customOptions: [ - // Pass the custom attachment picker options here - AttachmentPickerOption( - icon: const Icon(Icons.audiotrack), - supportedTypes: [AttachmentPickerType.audios], - optionViewBuilder: (context, attachmentPickerController) { - return AudioPicker( - onAudioPicked: (audio) async { - await attachmentPickerController.addAttachment(audio); - return Navigator.pop(context, attachmentPickerController.value); - }, - ); - }, - ), - ], - ); - ``` - -#### Attachment thumbnail size - -The size of the attachment thumbnail item shown in the gallery picker can be defined by passing the `attachmentThumbnailSize` parameter. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - attachmentThumbnailSize: const ThumbnailSize.square(600), - ); - ``` - -#### Attachment thumbnail format - -The format of the attachment thumbnail item shown in the gallery picker can be defined by passing the `attachmentThumbnailFormat` parameter. - -Possible values are `ThumbnailFormat.jpeg` and `ThumbnailFormat.png`. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - attachmentThumbnailFormat: ThumbnailFormat.jpeg, - ); - ``` - -#### Attachment thumbnail quality - -The quality of the attachment thumbnail item shown in the gallery picker can be defined by passing the `attachmentThumbnailQuality` parameter. - -Possible values are between 0 and 100. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - attachmentThumbnailQuality: 70, - ); - ``` - -#### Attachment thumbnail scale - -The scale of the attachment thumbnail item shown in the gallery picker can be defined by passing the `attachmentThumbnailScale` parameter. - -For example, if this is 2, it means that there are four image pixels for every one logical pixel, and the image's actual width and height are -double the height and width that should be used when painting the image. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - attachmentThumbnailScale: 2, - ); - ``` - -#### Additional modal bottom sheet parameters - -The `showStreamAttachmentPickerModalBottomSheet` function also accepts the parameters that are available in the `showModalBottomSheet` function. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - useRootNavigator: true, - elevation: 4, - isDismissible: true, - clipBehavior: Clip.antiAlias, - barrierColor: Colors.black.withOpacity(0.5), - constraints: const BoxConstraints( - maxHeight: 500, - maxWidth: 500, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(16), - ), - ), - ); - ``` - - - - - - diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/06-autocomplete_triggers.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/06-autocomplete_triggers.mdx deleted file mode 100644 index 601106dc99..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/06-autocomplete_triggers.mdx +++ /dev/null @@ -1,118 +0,0 @@ ---- -id: autocomplete_triggers -title: Autocomplete Triggers ---- - -Adding Custom Autocomplete Triggers - -### Introduction - -The [StreamMessageInput](../../03-stream_chat_flutter/stream_message_input.mdx) widget provides a way to add custom autocomplete triggers using the `StreamMessageInput.customAutocompleteTriggers` property. - -By default we provide autocomplete triggers for mentions and commands, but it's very easy to add your custom ones. - -### Add Emoji Autocomplete Trigger - -To add a custom emoji autocomplete trigger, you must first create an `AutoCompleteOptions` widget. -This widget will be used to show the autocomplete options. - -For this example we're using two external dependencies: - -- [emojis](https://pub.dev/packages/emojis) -- [`substring_highlight`](https://pub.dev/packages/substring_highlight) - -```dart -import 'package:emojis/emoji.dart'; -import 'package:flutter/material.dart'; - -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:substring_highlight/substring_highlight.dart'; - -/// Overlay for displaying emoji that can be used -class StreamEmojiAutocompleteOptions extends StatelessWidget { - /// Constructor for creating a [StreamEmojiAutocompleteOptions] - const StreamEmojiAutocompleteOptions({ - super.key, - required this.query, - this.onEmojiSelected, - }); - - /// Query for searching emoji. - final String query; - - /// Callback called when an emoji is selected. - final ValueSetter? onEmojiSelected; - - @override - Widget build(BuildContext context) { - final emojis = Emoji.all().where((it) { - final normalizedQuery = query.toUpperCase(); - final normalizedShortName = it.shortName.toUpperCase(); - - return normalizedShortName.contains(normalizedQuery); - }); - - if (emojis.isEmpty) return const SizedBox.shrink(); - - return StreamAutocompleteOptions( - options: emojis, - optionBuilder: (context, emoji) { - final themeData = Theme.of(context); - return ListTile( - dense: true, - horizontalTitleGap: 0, - leading: Text( - emoji.char, - style: themeData.textTheme.titleLarge!.copyWith( - fontSize: 24, - ), - ), - title: SubstringHighlight( - text: emoji.shortName, - term: query, - textStyleHighlight: themeData.textTheme.titleLarge!.copyWith( - color: Colors.yellow, - fontSize: 14.5, - fontWeight: FontWeight.bold, - ), - textStyle: themeData.textTheme.titleLarge!.copyWith( - fontSize: 14.5, - ), - ), - onTap: onEmojiSelected == null ? null : () => onEmojiSelected!(emoji), - ); - }, - ); - } -} -``` - -Now it's time to use the `StreamEmojiAutocompleteOptions` widget. - -```dart -StreamMessageInput( - customAutocompleteTriggers: [ - StreamAutocompleteTrigger( - trigger: ':', - minimumRequiredCharacters: 2, - optionsViewBuilder: ( - context, - autocompleteQuery, - messageEditingController, - ) { - final query = autocompleteQuery.query; - return StreamEmojiAutocompleteOptions( - query: query, - onEmojiSelected: (emoji) { - // accepting the autocomplete option. - StreamAutocomplete.of(context).acceptAutocompleteOption( - emoji.char, - keepTrigger: false, - ); - }, - ); - }, - ), - ], -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/07-slidable_channel_list_preview.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/07-slidable_channel_list_preview.mdx deleted file mode 100644 index 38bf429f6c..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/07-slidable_channel_list_preview.mdx +++ /dev/null @@ -1,212 +0,0 @@ ---- -id: slidable_channel_list_preview -title: Channel List Preview ---- - -Slidable Channel List Preview - -### Introduction - -The default slidable behavior within the channel list has been removed in v4 of the Stream Chat Flutter SDK. -This guide will show you how you can easily add this functionality yourself. - -Please see our [full v4 migration guide](../../05-guides/08-migrations/migration_guide_4_0.mdx) if you're migrating from an earlier version of the Stream Chat Flutter SDK. - -![Slidable demo](../../assets/slidable_demo.jpg) - -### Prerequisites - -This guide assumes you are familiar with the Stream Chat SDK. -If you're new to Stream Chat Flutter, we recommend looking at our [getting started tutorial](https://getstream.io/chat/flutter/tutorial/). - -**Dependencies:** - -```dart -dependencies: - flutter: - sdk: flutter - stream_chat_flutter: ^6.0.0 - flutter_slidable: ^3.0.0 -``` - -⚠️ Note: The examples shown in this guide use the above packages and versions. - -### Example Code - Custom Stream Channel Item Builder - -In this example, you are doing a few important things in the ChannelListPage widget. You're: - -- Using the **flutter_slidable** package to easily add slide functionality. -- Passing in the `itemBuilder` argument for the **StreamChannelListView** widget. This gives access to the current **BuildContext**, **Channel**, and **StreamChannelListTile**, and allows you to create, or customize, the stream channel list tiles. -- Returning a Slidable widget with two CustomSlidableAction widgets - to delete a channel and show more options. These widgets come from the flutter_slidable package. -- Adding `onPressed` behaviour to call `showConfirmationBottomSheet` and `showChannelInfoModalBottomSheet`. These methods come from the **`stream_chat_flutter`** package. They have a few different on-tap callbacks you can supply, for example, `onViewInfoTap`. Alternatively, you can create custom dialog screens from scratch. -- Using the **StreamChannelListController** to perform actions, such as, `deleteChannel`. - -```dart -import 'package:flutter/material.dart'; -import 'package:flutter_slidable/flutter_slidable.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -void main() async { - final client = StreamChatClient( - 's2dxdhpxd94g', - ); - - await client.connectUser( - User(id: 'super-band-9'), - '''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''', - ); - - 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: ChannelListPage( - client: client, - ), - ); - } -} - -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: SlidableAutoCloseBehavior( - child: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - itemBuilder: (context, channels, index, tile) { - final channel = channels[index]; - final chatTheme = StreamChatTheme.of(context); - final backgroundColor = chatTheme.colorTheme.inputBg; - final canDeleteChannel = channel.ownCapabilities - .contains(PermissionType.deleteChannel); - return Slidable( - groupTag: 'channels-actions', - endActionPane: ActionPane( - extentRatio: canDeleteChannel ? 0.40 : 0.20, - motion: const BehindMotion(), - children: [ - CustomSlidableAction( - onPressed: (_) { - showChannelInfoModalBottomSheet( - context: context, - channel: channel, - onViewInfoTap: () { - Navigator.pop(context); - // Navigate to info screen - }, - ); - }, - backgroundColor: backgroundColor, - child: const Icon(Icons.more_horiz), - ), - if (canDeleteChannel) - CustomSlidableAction( - backgroundColor: backgroundColor, - child: StreamSvgIcon.delete( - color: chatTheme.colorTheme.accentError, - ), - onPressed: (_) async { - final res = await showConfirmationBottomSheet( - context, - title: 'Delete Conversation', - question: - 'Are you sure you want to delete this conversation?', - okText: 'Delete', - cancelText: 'Cancel', - icon: StreamSvgIcon.delete( - color: chatTheme.colorTheme.accentError, - ), - ); - if (res == true) { - await _controller.deleteChannel(channel); - } - }, - ), - ], - ), - child: tile, - ); - }, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ), - ); -} - -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) => Scaffold( - appBar: const StreamChannelHeader(), - body: Column( - children: const [ - Expanded( - child: StreamMessageListView(), - ), - StreamMessageInput(), - ], - ), - ); -} -``` - -The above is the complete sample, and all you need for a basic implementation. diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/_category_.json b/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/_category_.json deleted file mode 100644 index 7dfd26e6ba..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/01-custom-widgets/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Custom Widgets" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/_category_.json b/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/_category_.json deleted file mode 100644 index b0b9ad39e8..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Customization" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/stream_chat_and_theming.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/stream_chat_and_theming.mdx deleted file mode 100644 index 46153e246f..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/02-customization/stream_chat_and_theming.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: stream_chat_and_theming -title: Theming ---- - -Understanding How To Customize Widgets Using `StreamChatTheme` - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChatTheme-class.html) and [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChatThemeData-class.html) - -### Background - -Stream's UI SDK makes it easy for developers to add custom styles and attributes to our widgets. Like most Flutter frameworks, Stream exposes a dedicated widget for theming. - -Using `StreamChatTheme`, users can customize most aspects of our UI widgets by setting attributes using `StreamChatThemeData`. - -Similar to the `Theme` and `ThemeData` in Flutter, Stream Chat uses a top level [inherited widget](https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html) to provide theming information throughout your application. This can be optionally set at the top of your application tree or at a localized point in your widget sub-tree. - -If you'd like to customize the look and feel of Stream chat across your entire application, we recommend setting your theme at the top level. Conversely, users can customize specific screens or widgets by wrapping components in a `StreamChatTheme`. - -### A closer look at StreamChatThemeData - -Looking at the constructor for `StreamChatThemeData`, 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 `ChannelHeader`, `MessageInputs`, etc. have been broken up into smaller theme objects. - -```dart -factory StreamChatThemeData({ - Brightness? brightness, - TextTheme? textTheme, - ColorTheme? colorTheme, - StreamChannelListHeaderThemeData? channelListHeaderTheme, - StreamChannelPreviewThemeData? channelPreviewTheme, - StreamChannelHeaderThemeData? channelHeaderTheme, - StreamMessageThemeData? otherMessageTheme, - StreamMessageThemeData? ownMessageTheme, - StreamMessageInputThemeData? messageInputTheme, - Widget Function(BuildContext, User)? defaultUserImage, - PlaceholderUserImage? placeholderUserImage, - IconThemeData? primaryIconTheme, - List? reactionIcons, - StreamGalleryHeaderThemeData? imageHeaderTheme, - StreamGalleryFooterThemeData? imageFooterTheme, - StreamMessageListViewThemeData? messageListViewTheme, - }); -``` - -### Stream Chat Theme in use - -Let's take a look at customizing widgets using `StreamChatThemeData`. In the example below, we can change the default color theme to yellow and override the channel header's typography and colors. - -```dart -MaterialApp( - builder: (context, child) => StreamChat( - client: client, - streamChatThemeData: StreamChatThemeData( - colorTheme: StreamColorTheme.light( - accentPrimary: const Color(0xffffe072), - ), - channelHeaderTheme: const ChannelHeaderThemeData( - color: const Color(0xffd34646), - titleStyle: TextStyle( - color: Colors.white, - ), - ), - ), - child: child, - ), -); -``` - -We are creating this class at the very top of our widget tree using the `streamChatThemeData` parameter found in the `StreamChat` widget. - -![](../assets/using_theme.jpg) diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/_category_.json b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/_category_.json deleted file mode 100644 index b323499b4c..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "UI Widgets" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/introduction.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/introduction.mdx deleted file mode 100644 index 8be1ffabe0..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/introduction.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -id: introduction -title: Introduction ---- - -Understanding The UI Package Of The Flutter SDK - -### What function does `stream_chat_flutter` serve? - -The UI SDK (`stream_chat_flutter`) contains official Flutter components for Stream Chat, a service for building chat applications. - -While the Stream Chat service provides the backend for messaging and the LLC provides an easy way to -use it in your Flutter apps, we wanted to make sure that adding Chat functionality to your app was as quick as possible. - -The UI package is built on top of the low-level client and the core package and allows you to build a -full fledged app with either the inbuilt components, modify existing components, or easily add widgets -of your own to match your app's style better. diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/setup.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/setup.mdx deleted file mode 100644 index b80e4b4d49..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/setup.mdx +++ /dev/null @@ -1,77 +0,0 @@ ---- -id: setup -title: Setup ---- - -Understanding Setup For `stream_chat_flutter` - -### Add pub.dev dependency - -First, you need to add the `stream_chat_flutter` dependency to your `pubspec.yaml`. - -You can either run this command: - -```shell -flutter pub add stream_chat_flutter -``` - -OR - -Add this line in the dependencies section of your `pubspec.yaml` after substituting the latest version: - -```yaml -dependencies: - stream_chat_flutter: ^latest_version -``` - -You can find the package details on [pub.dev](https://pub.dev/packages/stream_chat_flutter). - -### Details On Platform Support - -As of v5, the`stream_chat_flutter` package (UI) added support for web, macOS, Windows, and Linux - on top of the original support for Android and iOS. It has, however, been possible to target desktop and web since Flutter added support for these platforms using the `stream_chat_flutter_core` (builder) and `stream_chat` (low-level client) packages - this remains unchanged. - -Please note that Flutter Web may have additional constraints due to not supporting all plugins that Stream Chat relies on. The respective plugin creators will address this over time. - -### Setup - -This section provides setup instructions for the respective platforms. - -#### Android - -The package uses [`photo_manager`](https://pub.dev/packages/photo_manager) to access the device's photo library. Follow [this wiki](https://pub.dev/packages/photo_manager#android-10-q-29) to fulfill the Android requirements. - -#### iOS - -The library uses [flutter file picker plugin](https://github.com/miguelpruivo/flutter_file_picker) to pick -files from the os. Follow [this wiki](https://github.com/miguelpruivo/flutter_file_picker/wiki/Setup#ios) to fulfill iOS requirements. - -Stream Chat also uses the [`video_player`](https://pub.dev/packages/video_player) package to play videos. Follow [this guide](https://pub.dev/packages/video_player#installation) to fulfill the requirements. - -Stream Chat uses the [`image_picker`](https://pub.dev/packages/image_picker) plugin. -Follow [these instructions](https://pub.dev/packages/image_picker#ios) to check the requirements. - -#### Web - -For the web, edit your `index.html` and add the following in the `` tag to allow the SDK to override the right-click behavior: - -```html - -``` - -#### macOS - -For macOS Stream Chat uses the [`file_selector`](https://pub.dev/packages/file_selector#macos) package. Follow [these instructions](https://pub.dev/packages/file_selector#macos) to check the requirements. - -You also need to add the following [entitlements](https://docs.flutter.dev/development/platform-integration/desktop#entitlements-and-the-app-sandbox) to `Release.entitlement` and `DebugProfile.entitlement`: - -```xml -com.apple.security.network.client - -com.apple.security.files.user-selected.read-write - -``` - -Which grants: - -- Internet permission -- File access permission diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_channel_grid_view.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_channel_grid_view.mdx deleted file mode 100644 index 87ad4dc908..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_channel_grid_view.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: stream_channel_grid_view -title: StreamChannelGridView ---- - -A Widget For Displaying A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelGridView-class.html) - -### Background - -The `StreamChannelGridView` widget allows displaying a list of channels to a user in a `GridView`. - -:::note -Make sure to check the [StreamChannelListView](./stream_channel_list_view.mdx) documentation to know how to show results in a `ListView`. -::: - -### Basic Example - -Here is a basic example of the `StreamChannelGridView` widget. It consists of the main widget itself, a `StreamChannelListController` to control the list of channels and a callback to handle the tap of a channel. - -```dart -class ChannelGridPage extends StatefulWidget { - const ChannelGridPage({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - State createState() => _ChannelGridPageState(); -} - -class _ChannelGridPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelGridView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -This example by default displays the channels that a user is a part of. Now let's look at customizing -the widget. diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_channel_header.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_channel_header.mdx deleted file mode 100644 index 9e22272cc6..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_channel_header.mdx +++ /dev/null @@ -1,83 +0,0 @@ ---- -id: stream_channel_header -title: StreamChannelHeader ---- - -A Widget To Display Common Channel Details - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelHeader-class.html) - -![](../assets/channel_header.png) - -### Background - -When a user opens a channel, it is helpful to provide context of which channel they are in. This may -be in the form of a channel name or the users in the channel. Along with that, there also needs to be -a way for the user to look at more details of the channel (media, pinned messages, actions, etc.) and -preferably also a way to navigate back to where they came from. - -To encapsulate all of this functionality into one widget, the Flutter SDK contains a `StreamChannelHeader` -widget which provides these out of the box. - -### Basic Example - -Let's just add a `StreamChannelHeader` to a page with a `StreamMessageListView` and a `StreamMessageInput` to display -and send messages. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: const StreamChannelHeader(), - body: Column( - children: [ - Expanded( - child: StreamMessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, - ), - ), - const StreamMessageInput(), - ], - ), - ); - } -} -``` - -### Customizing Parts Of The Header - -The header works like a `ListTile` widget. - -Use the `title`, `subtitle`, `leading`, or `actions` parameters to substitute the widgets for your own. - -```dart -//... -StreamChannelHeader( - title: Text('My Custom Name'), -), -``` - -![](../assets/channel_header_custom_title.png) - -### Showing Connection State - -The `StreamChannelHeader` can also display connection state below the tile which shows the user if they -are connected or offline, etc. on connection events. - -To enable this, use the `showConnectionStateTile` property. - -```dart -//... -StreamChannelHeader( - showConnectionStateTile: true, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_channel_list_header.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_channel_list_header.mdx deleted file mode 100644 index b774ff0194..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_channel_list_header.mdx +++ /dev/null @@ -1,117 +0,0 @@ ---- -id: stream_channel_list_header -title: StreamChannelListHeader ---- - -A Header Widget For A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelListHeader-class.html) - -![](../assets/channel_list_header.png) - -### Background - -A common pattern for most messaging apps is to show a list of Channels (chats) on the first screen -and navigate to an individual one on being clicked. On this first page where the list of channels are -displayed, it is usual to have functionality such as adding a new chat, display the user logged in, etc. - -To encapsulate all of this functionality into one widget, the Flutter SDK contains a `StreamChannelListHeader` -widget which provides these out of the box. - -### Basic Example - -This is a basic example of a page which has a `StreamChannelListView` and a `StreamChannelListHeader` to recreate a -common Channels Page. - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - appBar: const StreamChannelListHeader(), - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -### Customizing Parts Of The Header - -The header works like a `ListTile` widget. - -Use the `titleBuilder`, `subtitle`, `leading`, or `actions` parameters to substitute the widgets for your own. - -```dart -//... -StreamChannelListHeader( - subtitle: Text('My Custom Subtitle'), -), -``` - -![](../assets/channel_list_header_custom_subtitle.png) - -The `titleBuilder` parameter helps you build different titles depending on the connection state: - -```dart -//... -StreamChannelListHeader( - titleBuilder: (context, status, client) { - switch(status) { - /// Return your title widget - } - }, -), -``` - -### Showing Connection State - -The `StreamChannelListHeader` can also display connection state below the tile which shows the user if they -are connected or offline, etc. on connection events. - -To enable this, use the `showConnectionStateTile` property. - -```dart -//... -StreamChannelListHeader( - showConnectionStateTile: true, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_channel_list_view.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_channel_list_view.mdx deleted file mode 100644 index 65058e4e5a..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_channel_list_view.mdx +++ /dev/null @@ -1,106 +0,0 @@ ---- -id: stream_channel_list_view -title: StreamChannelListView ---- - -A Widget For Displaying A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelListView-class.html) - -![](../assets/channel_list_view.png) - -### Background - -Channels are fundamental elements of Stream Chat and constitute shared spaces which allow users to -message each other. - -1:1 conversations and groups are both examples of channels, albeit with some (distinct/non-distinct) -differences. Displaying the list of channels that a user is a part of is a pattern present in most messaging apps. - -The `StreamChannelListView` widget allows displaying a list of channels to a user. By default, this is NOT -ONLY the channels that the user is a part of. This section goes into setting up and using a `StreamChannelListView` -widget. - -:::note -Make sure to check the [StreamChannelListController](../04-stream_chat_flutter_core/stream_channel_list_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamChannelListView`. -::: - -### Basic Example - -Here is a basic example of the `StreamChannelListView` widget. It consists of the main widget itself, a `StreamChannelListController` to control the list of channels and a callback to handle the tap of a channel. - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -This example by default displays the channels that a user is a part of. Now let's look at customizing -the widget. - -### Customizing the Channel Preview - -A common aspect of the widget needed to be tweaked according to each app is the Channel Preview (the -Channel tile in the list). To do this, we use the `itemBuilder` parameter like this: - -```dart -StreamChannelListView( - ... - itemBuilder: (context, channels, index, defaultTile) { - return ListTile( - tileColor: Colors.amberAccent, - title: Center( - child: StreamChannelName(channel: channels[index]), - ), - ); - }, -), -``` - -Which gives you a new Channel preview in the list: - -![](../assets/channel_preview.png) diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_member_grid_view.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_member_grid_view.mdx deleted file mode 100644 index 9115d8448b..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_member_grid_view.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -id: stream_member_grid_view -title: StreamMemberGridView ---- - -A widget for displaying and selecting members in a grid view. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMemberGridView-class.html) - -### Background - -The `StreamMemberGridView` widget allows displaying a list of members in a `GridView`. - -:::note -See the [StreamMemberListView](./stream_member_list_view.mdx) documentation for displaying members in a `ListView`. -::: - -### Basic Example - -```dart -class MemberGridPage extends StatefulWidget { - const MemberGridPage({ - super.key, - required this.client, - }); - - final Channel channel; - - @override - State createState() => _MemberGridPageState(); -} - -class _MemberGridPageState extends State { - late final _controller = StreamMemberListController( - channel: widget.channel, - limit: 25, - filter: Filter.and([ - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamMemberGridView( - controller: _controller, - onMemberTap: (member) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => Scaffold( - body: Center( - child: StreamUserAvatar( - user: member.user!, - ), - ), - ), - ), - ), - ), - ), - ); -} -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_member_list_view.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_member_list_view.mdx deleted file mode 100644 index 73662fde4e..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_member_list_view.mdx +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: stream_member_list_view -title: StreamMemberListView ---- - -A widget for displaying and selecting members in a list view. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMemberListView-class.html) - -### Background - -A list of members is required for many different purposes, for example, showing a list of users in a Channel. The `StreamMemberListView` displays a list of members. - -:::note -Make sure to check the [StreamMemberListController](../04-stream_chat_flutter_core/stream_member_list_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamMemberListView`. -::: - -### Basic Example - -```dart -class MemberListPage extends StatefulWidget { - const MemberListPage({super.key}); - - @override - State createState() => _MemberListPageState(); -} - -class _MemberListPageState extends State { - late final StreamMemberListController _memberListController = - StreamMemberListController( - channel: StreamChannel.of(context).channel, - limit: 25, - filter: Filter.and( - [Filter.notEqual('id', StreamChat.of(context).currentUser!.id)], - ), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - @override - Widget build(BuildContext context) { - return RefreshIndicator( - onRefresh: () => _memberListController.refresh(), - child: StreamMemberListView( - controller: _memberListController, - ), - ); - } -} -``` - -### Customize The Member Items - -You can use your own widget for the member items using the `itemBuilder` parameter. - -```dart -StreamMemberListView( - // ... - itemBuilder: (context, members, index, defaultWidget) { - return Text(members[index].user!.name); - }, -), -``` - -### Selecting Members - -The `StreamMemberListView` widget allows selecting members in a list. The `defaultWidget` returned can be customized to indicate that it has been selected. - -```dart -Set _selectedMembers = {}; - -StreamMemberListView( - controller: _memberListController, - itemBuilder: (context, members, index, defaultWidget) { - return defaultWidget.copyWith( - selected: _selectedMembers.contains(members[index]), - ); - }, - onMemberTap: (member) { - setState(() { - _selectedMembers.add(member); - }); - }, -); -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_message_input.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_message_input.mdx deleted file mode 100644 index a6c3c6640f..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_message_input.mdx +++ /dev/null @@ -1,112 +0,0 @@ ---- -id: stream_message_input -title: StreamMessageInput ---- - -A Widget Dealing With Everything Related To Sending A Message - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageInput-class.html) - -![](../assets/message_input.png) - -### Background - -In Stream Chat, we can send messages in a channel. However, sending a message isn't as simple as adding -a `TextField` and logic for sending a message. It involves additional processes like addition of media, -quoting a message, adding a custom command like a GIF board, and much more. Moreover, most apps also -need to customize the input to match their theme, overall color and structure pattern, etc. - -To do this, we created a `StreamMessageInput` widget which abstracts all expected functionality a modern input -needs - and allows you to use it out of the box. - -### Basic Example - -A `StreamChannel` is required above the widget tree in which the `StreamMessageInput` is rendered since the channel is -where the messages sent actually go. Let's look at a common example of how we could use the `StreamMessageInput`: - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: StreaChannelHeader(), - body: Column( - children: [ - Expanded( - child: StreamMessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, - ), - ), - StreamMessageInput(), - ], - ), - ); - } -} -``` - -It is common to put this widget in the same page of a `StreamMessageListView` as the bottom widget. - -:::note -Make sure to check the [StreamMessageInputController](../04-stream_chat_flutter_core/stream_message_input_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamMessageInput`. -::: - -### Adding Custom Actions - -By default, the `StreamMessageInput` has two actions: one for attachments and one for commands like Giphy. -To add your own action, we use the `actions` parameter like this: - -```dart -StreamMessageInput( - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20, - color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, - ), - onTap: () { - // Do something here - }, - ), - ], -), -``` - -This will add on your action to the existing ones. - -### Disable Attachments - -To disable attachments being added to the message, set the `disableAttachments` parameter to true. - -```dart -StreamMessageInput( - disableAttachments: true, -), -``` - -### Changing Position Of MessageInput Components - -You can also change the position of the TextField, actions and 'send' button relative to each other. - -To do this, use the `actionsLocation` or `sendButtonLocation` parameters which help you decide the location -of the buttons in the input. - -For example, if we want the actions on the right and the send button inside the TextField, we can do: - -```dart -StreamMessageInput( - sendButtonLocation: SendButtonLocation.inside, - actionsLocation: ActionsLocation.right, -), -``` - -![](../assets/message_input_change_position.png) diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_message_list_view.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_message_list_view.mdx deleted file mode 100644 index 5a3a247bb9..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_message_list_view.mdx +++ /dev/null @@ -1,91 +0,0 @@ ---- -id: stream_message_list_view -title: StreamMessageListView ---- - -A Widget For Displaying A List Of Messages - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageListView-class.html) - -![](../assets/message_list_view.png) - -### Background - -Every channel can contain a list of messages sent by users inside it. The `StreamMessageListView` widget -displays the list of messages inside a particular channel along with possible attachments and -other message attributes (if the message is pinned for example). This sets it apart from the `StreamMessageSearchListView` -which may not contain messages only from a single channel and is used to search for messages across -many. - -### Basic Example - -The `StreamMessageListView` shows the list of messages of the current channel. It has inbuilt support for -common messaging functionality: displaying and editing messages, adding / modifying reactions, support -for quoting messages, pinning messages, and more. - -An example of how you can use the `StreamMessageListView` is: - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: const StreamChannelHeader(), - body: Column( - children: [ - Expanded( - child: StreamMessageListView(), - ), - const StreamMessageInput(), - ], - ), - ); - } -} -``` - -### Enable Threads - -Threads are made of a parent message and replies linked to it. To enable threading, the SDK requires you -to supply a `threadBuilder` which will supply the page when the thread is clicked. - -```dart -StreamMessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, -), -``` - -![](../assets/message_list_view_threads.png) - -The `StreamMessageListView` itself can render the thread by supplying the `parentMessage` parameter. - -```dart -StreamMessageListView( - parentMessage: parent, -), -``` - -### Building Custom Messages - -You can also supply your own implementation for displaying messages using the `messageBuilder` parameter. - -:::note -To customize the existing implementation, look at the `StreamMessageWidget` documentation instead. -::: - -```dart -StreamMessageListView( - messageBuilder: (context, details, messageList, defaultImpl) { - // Your implementation of the message here - // E.g: return Text(details.message.text ?? ''); - }, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_message_search_grid_view.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_message_search_grid_view.mdx deleted file mode 100644 index 06e6cdea2b..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_message_search_grid_view.mdx +++ /dev/null @@ -1,60 +0,0 @@ ---- -id: stream_message_search_grid_view -title: StreamMessageSearchGridView ---- - -A Widget To Search For Messages Across Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageSearchGridView-class.html) - -### Background - -The `StreamMessageSearchGridView` widget allows displaying a list of searched messages in a `GridView`. - -:::note -Make sure to check the [StreamMessageSearchListView](./stream_message_search_list_view.mdx) documentation to know how to show results in a `ListView`. -::: - -### Basic Example - -```dart -class StreamMessageSearchPage extends StatefulWidget { - const StreamMessageSearchPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _StreamMessageSearchState(); -} - -class _StreamMessageSearchState extends State { - late final _controller = StreamMessageSearchListController( - client: widget.client, - limit: 20, - filter: Filter.in_( - 'members', - [StreamChat.of(context).user!.id], - ), - searchQuery: 'your query here', - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: StreamMessageSearchGridView( - controller: _controller, - itemBuilder: (context, values, index) { - // return your custom widget here - }, - ), - ); -} -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_message_search_list_view.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_message_search_list_view.mdx deleted file mode 100644 index 3aa5b75bd4..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_message_search_list_view.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -id: stream_message_search_list_view -title: StreamMessageSearchListView ---- - -A Widget To Search For Messages Across Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageSearchListView-class.html) - -![](../assets/message_search_list_view.png) - -### Background - -Users in Stream Chat can have several channels and it can get hard to remember which channel has the -message they are searching for. As such, there needs to be a way to search for a message across multiple -channels. This is where `StreamMessageSearchListView` comes in. - -:::note -Make sure to check the [StreamMessageSearchListController](../04-stream_chat_flutter_core/stream_message_search_list_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamMessageSearchListView`. -::: - -### Basic Example - -While the `StreamMessageListView` is tied to a certain `StreamChannel`, a `StreamMessageSearchListView` is not. - -```dart -class StreamMessageSearchPage extends StatefulWidget { - const StreamMessageSearchPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _StreamMessageSearchState(); -} - -class _StreamMessageSearchState extends State { - late final _controller = StreamMessageSearchListController( - client: widget.client, - limit: 20, - filter: Filter.in_( - 'members', - [StreamChat.of(context).user!.id], - ), - searchQuery: 'your query here', - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: StreamMessageSearchListView( - controller: _controller, - ), - ); -} -``` - -### Customize The Result Tiles - -You can use your own widget for the result items using the `itemBuilder` parameter. - -```dart -StreamMessageSearchListView( - // ... - itemBuilder: (context, responses, index, defaultWidget) { - return Text(responses[index].message.text); - }, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_message_widget.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_message_widget.mdx deleted file mode 100644 index e2da047751..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_message_widget.mdx +++ /dev/null @@ -1,99 +0,0 @@ ---- -id: stream_message_widget -title: StreamMessageWidget ---- - -A Widget For Displaying Messages And Attachments - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageWidget-class.html) - -### Background - -There are several things that need to be displayed with text in a message in a modern messaging app: -attachments, highlights if the message is pinned, user avatars of the sender, etc. - -To encapsulate all of this functionality into one widget, the Flutter SDK contains a `StreamMessageWidget` -widget which provides these out of the box. - -### Basic Example (Modifying `StreamMessageWidget` in `StreamMessageListView`) - -Primarily, the `StreamMessageWidget` is used in the `StreamMessageListView`. To customize only a few properties -of the `StreamMessageWidget` without supplying all other properties, the `messageBuilder` builder supplies -a default implementation of the widget for us to modify. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: StreamMessageListView( - messageBuilder: (context, details, messageList, defaultMessageWidget) { - return defaultMessageWidget.copyWith( - showThreadReplyIndicator: false, - ); - }, - ), - ); - } -} -``` - -### Building A Custom Attachment - -When a custom attachment type (location, audio, etc.) is sent, the MessageWidget also needs to know -how to build it. For this purpose, we can use the `customAttachmentBuilders` parameter. - -As an example, if a message has a attachment type 'location', we do: - -```dart -StreamMessageWidget( - //... - customAttachmentBuilders: { - 'location': (context, message, attachments) { - var attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'], - attachments[0].extraData['longitude'], - ), - ); - - return WrapAttachmentWidget( - attachmentWidget: attachmentWidget, - attachmentShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - ); - } - }, -) -``` - -You can also override the builder for existing attachment types like `image` and `video`. - -### Show User Avatar For Messages - -You can decide to show, hide, or remove user avatars of the sender of the message. To do this, set -the `showUserAvatar` property like this: - -```dart -StreamMessageWidget( - //... - showUserAvatar = DisplayWidget.show, -) -``` - -### Reverse the message - -In most cases, `StreamMessageWidget` needs to be a different orientation depending upon if the sender is the -user or someone else. - -For this, we use the `reverse` parameter to change the orientation of the message: - -```dart -StreamMessageWidget( - //... - reverse = true, -) -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_user_grid_view.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_user_grid_view.mdx deleted file mode 100644 index b858cc4844..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_user_grid_view.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -id: stream_user_grid_view -title: StreamUserGridView ---- - -A Widget For Displaying And Selecting Users - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamUserGridView-class.html) - -### Background - -The `StreamUserGridView` widget allows displaying a list of users in a `GridView`. - -:::note -Make sure to check the [StreamUserListView](./stream_user_list_view.mdx) documentation to know how to show results in a `ListView`. -::: - -### Basic Example - -```dart -class UserGridPage extends StatefulWidget { - const UserGridPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _UserGridPageState(); -} - -class _UserGridPageState extends State { - late final _controller = StreamUserListController( - client: widget.client, - limit: 25, - filter: Filter.and([ - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamUserGridView( - controller: _controller, - onMemberTap: (member) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => Scaffold( - body: Center( - child: StreamUserAvatar( - user: member.user!, - ), - ), - ), - ), - ), - ), - ), - ); -} -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_user_list_view.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_user_list_view.mdx deleted file mode 100644 index eb3b8b635f..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/03-stream_chat_flutter/stream_user_list_view.mdx +++ /dev/null @@ -1,93 +0,0 @@ ---- -id: stream_user_list_view -title: StreamUserListView ---- - -A Widget For Displaying And Selecting Users - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamUserListView-class.html) - -![](../assets/user_list_view.png) - -### Background - -A list of users is required for many different purposes: showing a list of users in a Channel, -selecting users to add in a channel, etc. The `StreamUserListView` displays a list -of users. - -:::note -Make sure to check the [StreamUserListController](../04-stream_chat_flutter_core/stream_user_list_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamUserListView`. -::: - -### Basic Example - -```dart -class UserListPage extends StatefulWidget { - const UserListPage({super.key}); - - @override - State createState() => _UserListPageState(); -} - -class _UserListPageState extends State { - late final StreamUserListController _userListController = - StreamUserListController( - client: StreamChat.of(context).client, - limit: 25, - filter: Filter.and( - [Filter.notEqual('id', StreamChat.of(context).currentUser!.id)], - ), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - @override - Widget build(BuildContext context) { - return RefreshIndicator( - onRefresh: () => _userListController.refresh(), - child: StreamUserListView( - controller: _userListController, - ), - ); - } -} -``` - -### Customize The User Items - -You can use your own widget for the user items using the `itemBuilder` parameter. - -```dart -StreamUsersListView( - // ... - itemBuilder: (context, users, index, defaultWidget) { - return Text(users[index].name); - }, -), -``` - -### Selecting Users - -The `StreamUserListView` widget allows selecting users in a list. The `defaultWidget` returned can be customized to indicate that it has been selected. - -```dart -Set _selectedUsers = {}; - -StreamUserListView( - controller: _userListController, - itemBuilder: (context, users, index, defaultWidget) { - return defaultWidget.copyWith( - selected: _selectedUsers.contains(users[index]), - ); - }, - onUserTap: (user) { - setState(() { - _selectedUsers.add(user); - }); - }, -); -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/_category_.json b/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/_category_.json deleted file mode 100644 index 9737db7583..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Core Widgets" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/introduction.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/introduction.mdx deleted file mode 100644 index a59faf1017..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/introduction.mdx +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: introduction -title: Introduction ---- - -Understanding The Core Package Of The Flutter SDK - -This package provides business logic to fetch common things required for integrating Stream Chat into your application. -The core package allows more customisation and hence provides business logic but no UI components. -Please use the `stream_chat_flutter` package for the full fledged suite of UI components or `stream_chat` for the low-level client. - -### Background - -In the early days of the Flutter SDK, the SDK was only split into the LLC (`stream_chat`) and -the UI package (`stream_chat_flutter`). With this you could use a fully built interface with the UI package -or a fully custom interface with the LLC. However, we soon recognised the need for a third intermediary -package which made tasks like building and modifying a list of channels or messages easy but without -the complexity of using low level components. The Core package (`stream_chat_flutter_core`) is a manifestation -of the same idea and allows you to build an interface with Stream Chat without having to deal with -low level code and architecture as well as implementing your own theme and UI effortlessly. -Also, it has very few dependencies. - -We will now explore the components of this intermediary package and understand how it helps you build -the experience you want your users to have. - -The package primarily contains a bunch of controller classes. -Controllers are used to handle the business logic of the chat. You can use them together with our UI widgets, or you can even use them to build your own UI. - -* StreamChannelListController -* StreamUserListController -* StreamMessageSearchListController -* StreamMessageInputController -* LazyLoadScrollView -* PagedValueListenableBuilder - -This section goes into the individual core package widgets and their functional use. diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/lazy_load_scroll_view.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/lazy_load_scroll_view.mdx deleted file mode 100644 index 0a5a96bf7c..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/lazy_load_scroll_view.mdx +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: lazy_load_scroll_view -title: LazyLoadScrollView ---- - -A Widget For Building A Paginated List - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/LazyLoadScrollView-class.html) - -### Background - -The `LazyLoadScrollView` is a widget that helps you build a paginated list. -It provides callbacks to notify you when the list has been scrolled to the bottom and when the list has been scrolled to the top and other necessary callbacks. - -#### Callbacks - -* onStartOfPage: called when the list has been scrolled to the top of the page. - -* onEndOfPage: called when the list has been scrolled to the bottom of the page. - -* onPageScrollStart: called when the scroll of the list starts. - -* onPageScrollEnd: called when the scroll of the list ends. - -* onInBetweenOfPage: called when the list is not either at the top nor at the bottom of the page. - -### Basic Example - -Building a paginated list is a very common task. Here is an example of how to use the `LazyLoadScrollView` to build a simple list with pagination. - -```dart -LazyLoadScrollView( - onEndOfPage: _paginateData, - /// The child could be any widget which dispatches [ScrollNotification]s. - /// For example [ListView], [GridView] or [CustomScrollView]. - child: ListView.builder( - itemBuilder: (context, index) => _buildListTile, - ), -) -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/message_list_core.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/message_list_core.mdx deleted file mode 100644 index 394c129a9f..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/message_list_core.mdx +++ /dev/null @@ -1,71 +0,0 @@ ---- -id: message_list_core -title: MessageListCore ---- - -A Widget For Building A List Of Messages - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/MessageListCore-class.html) - -### Background - -The UI SDK of Stream Chat supplies a `MessageListView` class that builds a list of channels fetching -according to the filters and sort order given. However, in some cases, implementing novel UI is necessary -that cannot be done using the customization approaches given in the widget. - -To do this, we extracted the logic required for fetching channels into a 'Core' widget - a widget that -fetches channels in the expected way via the usual parameters but does not supply any UI and instead -exposes builders to build the UI in situations such as loading, empty data, errors, and on data received. - -### Basic Example - -`MessageListCore` is a simplified class that allows fetching a list of -messages while exposing UI builders. - -This allows you to construct your own UI while not having to -worry about the specific logic of fetching messages in a channel. - -A `MessageListController` is used to paginate data. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Column( - children: [ - Expanded( - child: MessageListCore( - emptyBuilder: (context) { - return const Center( - child: Text('Nothing here...'), - ); - }, - loadingBuilder: (context) { - return const Center( - child: CircularProgressIndicator(), - ); - }, - messageListBuilder: (context, list) { - return MessagesPage(list); - }, - errorBuilder: (context, err) { - return const Center( - child: Text('Error'), - ); - }, - ), - ), - ], - ), - ); - } -} -``` - -Make sure to have a `StreamChannel` ancestor in order to provide the -information about the channels. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/paged_value_listenable_builder.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/paged_value_listenable_builder.mdx deleted file mode 100644 index 18b54f6104..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/paged_value_listenable_builder.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -id: paged_value_listenable_builder -title: PagedValueListenableBuilder ---- - -A Widget Whose Content Stays Synced With A `ValueNotifier` Of Type `PagedValue`. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/PagedValueListenableBuilder-class.html) - -### Background - -Given a `PagedValueNotifier` implementation and a [builder] which builds widgets from -concrete values of `PagedValue`, this class will automatically register itself as a -listener of the [PagedValueNotifier] and call the [builder] with updated values -when the value changes. - -### Basic Example - -```dart -class UserNameValueNotifier extends PagedValueNotifier { - UserNameValueNotifier() : super(const PagedValue.loading()); - - @override - Future doInitialLoad() async { - // Imitating network delay - await Future.delayed(const Duration(seconds: 1)); - value = const PagedValue( - items: ['Sahil', 'Salvatore', 'Reuben'], - - /// Passing the key to load the next page - nextPageKey: nextPageKey, - ); - } - - @override - Future loadMore(int nextPageKey) async { - // Imitating network delay - await Future.delayed(const Duration(seconds: 1)); - final previousItems = value.asSuccess.items; - final newItems = previousItems + ['Deven', 'Sacha', 'Gordon']; - value = PagedValue( - items: newItems, - // Passing nextPageKey as null to indicate - // that there are no more items. - nextPageKey: null, - ); - } -} - -class _MyHomePageState extends State { - final pagedValueNotifier = UserNameValueNotifier(); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Center( - child: PagedValueListenableBuilder( - builder: (context, value, child) { - // This builder will only get called when the _counter - // is updated. - return value.when( - (userNames, nextPageKey, error) => Column( - children: [ - const Text('Usernames:'), - Expanded( - child: ListView( - children: userNames.map(Text.new).toList(), - ), - ), - if (nextPageKey != null) - TextButton( - child: const Text('Load more'), - onPressed: () => pagedValueNotifier.loadMore(nextPageKey), - ), - ], - ), - loading: CircularProgressIndicator.new, - error: (e) => Text('Error: $e'), - ); - }, - valueListenable: pagedValueNotifier, - ), - ), - ); - } -} -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/setup.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/setup.mdx deleted file mode 100644 index f297484274..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/setup.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -id: setup -title: Setup ---- - -Understanding Setup For `stream_chat_flutter_core` - -### Add pub.dev dependency - -First, you need to add the `stream_chat_flutter_core` dependency to your pubspec.yaml - -You can either run this command: - -```shell -flutter pub add stream_chat_flutter_core -``` - -OR - -Add this line in the dependencies section of your pubspec.yaml after substituting latest version: - -```yaml -dependencies: - stream_chat_flutter_core: ^latest_version -``` - -You can find the package details on [pub.dev](https://pub.dev/packages/stream_chat_flutter_core). diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_channel_list_controller.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_channel_list_controller.mdx deleted file mode 100644 index f97c390a59..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_channel_list_controller.mdx +++ /dev/null @@ -1,152 +0,0 @@ ---- -id: stream_channel_list_controller -title: StreamChannelListController ---- - -A Widget For Controlling A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamChannelListController-class.html) - -### Background - -The `StreamChannelListController` is a controller class that allows you to control a list of channels. -`StreamChannelListController` is a required parameter of the `StreamChannelListView` widget. -Check the [`StreamChannelListView` documentation](../03-stream_chat_flutter/stream_channel_list_view.mdx) to read more about that. - -The `StreamChannelListController` also listens for various events and manipulates the current list of channels accordingly. -Passing a `StreamChannelListEventHandler` to the `StreamChannelListController` will allow you to customize this behaviour. - -### Basic Example - -Building a custom channel list is a very common task. Here is an example of how to use the `StreamChannelListController` to build a simple list with pagination. - -First of all we should create an instance of the `StreamChannelListController` and provide it with the `StreamChatClient` instance. -You can also add a `Filter`, a list of `SortOption`s and other pagination-related parameters. - -```dart -class _MyChannelListPageState extends State { - /// Controller used for loading more data and controlling pagination in - /// [StreamChannelListController]. - late final channelListController = StreamChannelListController( - client: StreamChatCore.of(context).client, - filter: Filter.and([ - Filter.equal('type', 'messaging'), - Filter.in_( - 'members', - [ - StreamChatCore.of(context).currentUser!.id, - ], - ), - ]), - ); - ... -} -``` - -Make sure you call `channelListController.doInitialLoad()` to load the initial data and `channelListController.dispose()` when the controller is no longer required. - -```dart -@override -void initState() { - channelListController.doInitialLoad(); - super.initState(); -} - -@override -void dispose() { - channelListController.dispose(); - super.dispose(); -} -``` - -The `StreamChannelListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of channels has changed. -You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest channels. - -```dart -@override -Widget build(BuildContext context) => Scaffold( - body: PagedValueListenableBuilder( - valueListenable: channelListController, - builder: (context, value, child) { - return value.when( - (channels, nextPageKey, error) => LazyLoadScrollView( - onEndOfPage: () async { - if (nextPageKey != null) { - channelListController.loadMore(nextPageKey); - } - }, - child: ListView.builder( - /// We're using the channels length when there are no more - /// pages to load and there are no errors with pagination. - /// In case we need to show a loading indicator or and error - /// tile we're increasing the count by 1. - itemCount: (nextPageKey != null || error != null) - ? channels.length + 1 - : channels.length, - itemBuilder: (BuildContext context, int index) { - if (index == channels.length) { - if (error != null) { - return TextButton( - onPressed: () { - channelListController.retry(); - }, - child: Text(error.message), - ); - } - return const CircularProgressIndicator(); - } - - final _item = channels[index]; - return ListTile( - title: Text(_item.name ?? ''), - subtitle: StreamBuilder( - stream: _item.state!.lastMessageStream, - initialData: _item.state!.lastMessage, - builder: (context, snapshot) { - if (snapshot.hasData) { - return Text(snapshot.data!.text!); - } - - return const SizedBox(); - }, - ), - onTap: () { - /// Display a list of messages when the user taps on - /// an item. We can use [StreamChannel] to wrap our - /// [MessageScreen] screen with the selected channel. - /// - /// This allows us to use a built-in inherited widget - /// for accessing our `channel` later on. - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: _item, - child: const MessageScreen(), - ), - ), - ); - }, - ); - }, - ), - ), - loading: () => const Center( - child: SizedBox( - height: 100, - width: 100, - child: CircularProgressIndicator(), - ), - ), - error: (e) => Center( - child: Text( - 'Oh no, something went wrong. ' - 'Please check your config. $e', - ), - ), - ); - }, - ), - ); -``` - -In this case we're using the [`LazyLoadScrollView`](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_channel_list_event_handler.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_channel_list_event_handler.mdx deleted file mode 100644 index 1b272c51b0..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_channel_list_event_handler.mdx +++ /dev/null @@ -1,54 +0,0 @@ ---- -id: stream_channel_list_event_handler -title: StreamChannelListEventHandler ---- - -A Class To Customize The Event Handler For The StreamChannelListController. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamChannelListEventHandler-class.html) - -### Background - -A `StreamChannelListEventHandler` is a class that handles the events that are related to the channel list loaded by `StreamChannelListController`. -The `StreamChannelListController` automatically creates a `StreamChannelListEventHandler` internally and handles the events. In order to provide a custom -implementation of `StreamChannelListEventHandler`, you need to create a class that extends the `StreamChannelListEventHandler` class. - -### Basic Example - -There are 2 ways to provide a custom implementation of `StreamChannelListEventHandler`: - -* Create a class that extends the `StreamChannelListEventHandler` and pass it down to the controller. - -```dart -class MyCustomEventHandler extends StreamChannelListEventHandler { - @override - void onConnectionRecovered( - Event event, - StreamChannelListController controller, - ) { - // Write your own custom implementation here - } -} -``` - -Pass it down to the controller: - -```dart - late final listController = StreamChannelListController( - client: StreamChat.of(context).client, - eventHandler: MyCustomEventHandler(), - ); -``` - -* Mix the `StreamChannelListEventHandler` into your widget state. - -```dart -class _ChannelListPageState extends State { - - late final _listController = StreamChannelListController( - client: StreamChat.of(context).client, - eventHandler: MyCustomEventHandler(), - ); -} -``` - diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_chat_core.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_chat_core.mdx deleted file mode 100644 index f93283ac4b..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_chat_core.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -id: stream_chat_core -title: StreamChatCore ---- - -`StreamChatCore` is a version of `StreamChat` found in `stream_chat_flutter` that is decoupled from -theme and initialisations. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamChatCore-class.html) - -`StreamChatCore` is used to provide information about the chat client to the widget tree. -This Widget is used to react to life cycle changes and system updates. -When the app goes into the background, the web socket connection is automatically closed and when it goes back to foreground the connection is opened again. - -Like the `StreamChat` widget in the higher level UI package, the `StreamChatCore` widget should -be on the top level before using any Stream functionality: - -```dart -return MaterialApp( - title: 'Stream Chat Core Example', - home: HomeScreen(), - builder: (context, child) => StreamChatCore( - client: client, - child: child, - ), - ); -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_member_list_controller.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_member_list_controller.mdx deleted file mode 100644 index 159e731859..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_member_list_controller.mdx +++ /dev/null @@ -1,111 +0,0 @@ ---- -id: stream_member_list_controller -title: StreamMemberListController ---- - -A widget for controlling a list of members. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamMemberListController-class.html) - -### Background - -The `StreamMemberListController` is a controller class that allows you to control a list of users. -`StreamMemberListController` is a required parameter of the `StreamMemberListView` widget. -Check the [`StreamMemberListView` documentation](../03-stream_chat_flutter/stream_member_list_view.mdx) to read more about that. - -### Basic Example - -Building a custom member list is a very common task. Here is an example of how to use the `StreamMemberListController` to build a simple list with pagination. - -First, create an instance of the `StreamMemberListController` and provide it with the `StreamChatClient` instance. -You can also add a `Filter`, a list of `SortOption`s, and other pagination-related parameters. - -```dart -class MemberListPageState extends State { - /// Controller used for loading more data and controlling pagination in - /// [StreamMemberListController]. - late final memberListController = StreamMemberListController( - channel: StreamChannel.of(context).channel, - ); -``` - -Make sure you call `memberListController.doInitialLoad()` to load the initial data and `memberListController.dispose()` when the controller is no longer required. - -```dart -@override -void initState() { - memberListController.doInitialLoad(); - super.initState(); -} - -@override -void dispose() { - memberListController.dispose(); - super.dispose(); -} -``` - -The `StreamMemberListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of members has changed. -You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest members. - -```dart -@override -Widget build(BuildContext context) => Scaffold( - body: PagedValueListenableBuilder( - valueListenable: memberListController, - builder: (context, value, child) { - return value.when( - (members, nextPageKey, error) => LazyLoadScrollView( - onEndOfPage: () async { - if (nextPageKey != null) { - memberListController.loadMore(nextPageKey); - } - }, - child: ListView.builder( - /// We're using the members length when there are no more - /// pages to load and there are no errors with pagination. - /// In case we need to show a loading indicator or and error - /// tile we're increasing the count by 1. - itemCount: (nextPageKey != null || error != null) - ? members.length + 1 - : members.length, - itemBuilder: (BuildContext context, int index) { - if (index == members.length) { - if (error != null) { - return TextButton( - onPressed: () { - memberListController.retry(); - }, - child: Text(error.message), - ); - } - return const CircularProgressIndicator(); - } - - final _item = members[index]; - return ListTile( - title: Text(_item.user?.name ?? ''), - ); - }, - ), - ), - loading: () => const Center( - child: SizedBox( - height: 100, - width: 100, - child: CircularProgressIndicator(), - ), - ), - error: (e) => Center( - child: Text( - 'Oh no, something went wrong. ' - 'Please check your config. $e', - ), - ), - ); - }, - ), - ); -``` - -In this case, we're using the [LazyLoadScrollView](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list. diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_message_input_controller.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_message_input_controller.mdx deleted file mode 100644 index 6b0c41add9..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_message_input_controller.mdx +++ /dev/null @@ -1,88 +0,0 @@ ---- -id: stream_message_input_controller -title: StreamMessageInputController ---- - -A Widget For Controlling A Message Input - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamMessageInputController-class.html) - -### Background - -The `StreamMessageInputController` is a controller class that embed the business logic to compose a message. -`StreamMessageInputController` is a parameter of the `StreamMessageInput` widget. -Check the [`StreamMessageInput` documentation](../03-stream_chat_flutter/stream_message_input.mdx) to read more about that. - -### Basic Example - -Building a custom message input is a common task. Here is an example of how to use the `StreamMessageInputController` to build a simple custom message input widget. - -First of all we should create an instance of the `StreamMessageInputController`. - -```dart -class MessageScreenState extends State { - final StreamMessageInputController messageInputController = StreamMessageInputController(); -``` - -Make sure you call `messageInputController.dispose()` when the controller is no longer required. - -```dart -@override -void dispose() { - messageInputController.dispose(); - super.dispose(); -} -``` - -The `StreamMessageInputController` is basically a `ValueNotifier` that notifies you when the message being composed has changed. -You can use a `ValueListenableBuilder` to build your UI depending on the latest message. -For a very simple message input you could even pass the `messageInputController.textEditingController` to your `TextField` and set the `onChanged` callback. - -```dart -... -Padding( - padding: const EdgeInsets.all(8), - child: Row( - children: [ - Expanded( - child: TextField( - controller: messageInputController.textFieldController, - onChanged: (s) => messageInputController.text = s, - decoration: const InputDecoration( - hintText: 'Enter your message', - ), - ), - ), - Material( - type: MaterialType.circle, - color: Colors.blue, - clipBehavior: Clip.hardEdge, - child: InkWell( - onTap: () async { - if (messageInputController.message.text?.isNotEmpty == - true) { - await channel.sendMessage( - messageInputController.message, - ); - messageInputController.clear(); - if (context.mounted) { - _updateList(); - } - } - }, - child: const Padding( - padding: EdgeInsets.all(8), - child: Center( - child: Icon( - Icons.send, - color: Colors.white, - ), - ), - ), - ), - ), - ], - ), -), -... -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_message_search_list_controller.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_message_search_list_controller.mdx deleted file mode 100644 index 474661900c..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_message_search_list_controller.mdx +++ /dev/null @@ -1,126 +0,0 @@ ---- -id: stream_message_search_list_controller -title: StreamMessageSearchListController ---- - -A Widget For Controlling A List Of Searched Messages - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamMessageSearchListController-class.html) - -### Background - -The `StreamMessageSearchListController` is a controller class that allows you to control a list of searched messages. -`StreamMessageSearchListController` is a required parameter of the `StreamMessageSearchListView` widget. -Check the [`StreamMessageSearchListView` documentation](../03-stream_chat_flutter/stream_message_search_list_view.mdx) to read more about that. - -### Basic Example - -Building a custom message search feature is a common task. Here is an example of how to use the `StreamMessageSearchListController` to build a simple search list with pagination. - -First of all we should create an instance of the `StreamMessageSearchListController` and provide it with the `StreamChatClient` instance. -You can also add a `Filter`, a list of `SortOption`s and other pagination-related parameters. - -```dart -class SearchListPageState extends State { - /// Controller used for loading more data and controlling pagination in - /// [StreamMessageSearchListController]. - late final messageSearchListController = StreamMessageSearchListController( - client: StreamChatCore.of(context).client, - ); -``` - -Make sure you call `messageSearchListController.doInitialLoad()` to load the initial data and `messageSearchListController.dispose()` when the controller is no longer required. - -```dart -@override -void initState() { - messageSearchListController.doInitialLoad(); - super.initState(); -} - -@override -void dispose() { - messageSearchListController.dispose(); - super.dispose(); -} -``` - -The `StreamMessageSearchListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of responses has changed. -You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest responses. - -```dart -@override -Widget build(BuildContext context) => Scaffold( - body: Column( - children: [ - TextField( - /// This is just a sample implementation of a search field. - /// In a real-world app you should throttle the search requests. - /// You can use our library [rate_limiter](https://pub.dev/packages/rate_limiter). - onChanged: (s) { - messageSearchListController..searchQuery = s..doInitialLoad(); - }, - ), - Expanded( - child: PagedValueListenableBuilder( - valueListenable: messageSearchListController, - builder: (context, value, child) { - return value.when( - (responses, nextPageKey, error) => LazyLoadScrollView( - onEndOfPage: () async { - if (nextPageKey != null) { - messageSearchListController.loadMore(nextPageKey); - } - }, - child: ListView.builder( - /// We're using the responses length when there are no more - /// pages to load and there are no errors with pagination. - /// In case we need to show a loading indicator or and error - /// tile we're increasing the count by 1. - itemCount: (nextPageKey != null || error != null) - ? responses.length + 1 - : responses.length, - itemBuilder: (BuildContext context, int index) { - if (index == responses.length) { - if (error != null) { - return TextButton( - onPressed: () { - messageSearchListController.retry(); - }, - child: Text(error.message), - ); - } - return const CircularProgressIndicator(); - } - - final _item = responses[index]; - return ListTile( - title: Text(_item.channel?.name ?? ''), - subtitle: Text(_item.message.text ?? ''), - ); - }, - ), - ), - loading: () => const Center( - child: SizedBox( - height: 100, - width: 100, - child: CircularProgressIndicator(), - ), - ), - error: (e) => Center( - child: Text( - 'Oh no, something went wrong. ' - 'Please check your config. $e', - ), - ), - ); - }, - ), - ), - ], - ), - ); -``` - -In this case we're using the [`LazyLoadScrollView`](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_user_list_controller.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_user_list_controller.mdx deleted file mode 100644 index d06baa56e9..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/04-stream_chat_flutter_core/stream_user_list_controller.mdx +++ /dev/null @@ -1,111 +0,0 @@ ---- -id: stream_user_list_controller -title: StreamUserListController ---- - -A Widget For Controlling A List Of Users - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamUserListController-class.html) - -### Background - -The `StreamUserListController` is a controller class that allows you to control a list of users. -`StreamUserListController` is a required parameter of the `StreamUserListView` widget. -Check the [`StreamUserListView` documentation](../03-stream_chat_flutter/stream_user_list_view.mdx) to read more about that. - -### Basic Example - -Building a custom user list is a very common task. Here is an example of how to use the `StreamUserListController` to build a simple list with pagination. - -First of all we should create an instance of the `StreamUserListController` and provide it with the `StreamChatClient` instance. -You can also add a `Filter`, a list of `SortOption`s and other pagination-related parameters. - -```dart -class UserListPageState extends State { - /// Controller used for loading more data and controlling pagination in - /// [StreamUserListController]. - late final userListController = StreamUserListController( - client: StreamChatCore.of(context).client, - ); -``` - -Make sure you call `userListController.doInitialLoad()` to load the initial data and `userListController.dispose()` when the controller is no longer required. - -```dart -@override -void initState() { - userListController.doInitialLoad(); - super.initState(); -} - -@override -void dispose() { - userListController.dispose(); - super.dispose(); -} -``` - -The `StreamUserListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of users has changed. -You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest users. - -```dart -@override -Widget build(BuildContext context) => Scaffold( - body: PagedValueListenableBuilder( - valueListenable: userListController, - builder: (context, value, child) { - return value.when( - (users, nextPageKey, error) => LazyLoadScrollView( - onEndOfPage: () async { - if (nextPageKey != null) { - userListController.loadMore(nextPageKey); - } - }, - child: ListView.builder( - /// We're using the users length when there are no more - /// pages to load and there are no errors with pagination. - /// In case we need to show a loading indicator or and error - /// tile we're increasing the count by 1. - itemCount: (nextPageKey != null || error != null) - ? users.length + 1 - : users.length, - itemBuilder: (BuildContext context, int index) { - if (index == users.length) { - if (error != null) { - return TextButton( - onPressed: () { - userListController.retry(); - }, - child: Text(error.message), - ); - } - return const CircularProgressIndicator(); - } - - final _item = users[index]; - return ListTile( - title: Text(_item.name), - ); - }, - ), - ), - loading: () => const Center( - child: SizedBox( - height: 100, - width: 100, - child: CircularProgressIndicator(), - ), - ), - error: (e) => Center( - child: Text( - 'Oh no, something went wrong. ' - 'Please check your config. $e', - ), - ), - ); - }, - ), - ); -``` - -In this case we're using the [`LazyLoadScrollView`](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/01-understanding_filters.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/01-understanding_filters.mdx deleted file mode 100644 index 152a8a8fee..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/01-understanding_filters.mdx +++ /dev/null @@ -1,193 +0,0 @@ ---- -id: understanding_filters -title: Filters ---- - -Understanding Filters - -### Introduction - -Filters are used to get a specific subset of objects (channels, users, messages, members, etc) which -fit the conditions specified. Earlier versions of the SDK contained String-based filters which are now replaced by type-safe -filters. This guide aims to explain the different types of filters and how to use them. - -### Types Of Filters - -#### Filter.equal - -The 'equal' filter gets the objects where the given key has the specified value. - -```dart -Filter.equal('type', 'messaging'), -``` - -#### Filter.notEqual - -The `notEqual` filter gets the objects where the given key does not have the specified value. - -```dart -Filter.notEqual('type', 'messaging'), -``` - -#### Filter.greater - -The 'greater' filter gets the objects where the given key has a higher value than the specified value. - -```dart -Filter.greater('count', 5), -``` - -#### Filter.greaterOrEqual - -The 'greaterOrEqual' filter gets the objects where the given key has an equal or higher value than the specified value. - -```dart -Filter.greaterOrEqual('count', 5), -``` - -#### Filter.less - -The 'less' filter gets the objects where the given key has a lesser value than the specified value. - -```dart -Filter.less('count', 5), -``` - -#### Filter.lessOrEqual - -The 'lessOrEqual' filter gets the objects where the given key has a lesser or equal value than the specified value. - -```dart -Filter.lessOrEqual('count', 5), -``` - -#### Filter.in_ - -The `in_` filter allows getting objects where the key matches any in a specified array. - -```dart -Filter.in_('members', [user.id]) -``` - -:::note -Since 'in' is a keyword in Dart, the filter has an underscore added. This does not apply to the `notIn` -keyword. -::: - -#### Filter.notIn - -The `notIn` filter allows getting objects where the key matches none in a specified array. - -```dart -Filter.notIn('members', [user.id]) -``` - -#### Filter.query - -The 'query' filter matches values by performing text search with the specified value. - -```dart -Filter.query('name', 'demo') -``` - -#### Filter.autoComplete - -The 'autoComplete' filter matches values with the specified prefix. - -```dart -Filter.autoComplete('name', 'demo') -``` - -#### Filter.exists - -The 'exists' filter matches values that exist, or don't exist, based on the specified boolean value. - -```dart -Filter.exists('name') -``` - -#### Filter.notExists - -The `notExists` filter checks if the specified key doesn't exist. This is a simplified call to `Filter.exists` -with the value set to false. - -```dart -Filter.notExists('name') -``` - -#### Filter.contains - -The 'contains' filter matches any list that contains the specified value. - -```dart -Filter.contains('teams', 'red') -``` - -#### Filter.empty - -The 'empty' filter constructor returns an empty filter. It's the equivalent of an empty map `{}`; - -```dart -Filter.empty(); -``` - -#### Filter.raw - -The 'raw' filter constructor lets you specify a raw filter. We suggest using this only if you can't manage to build what you want using the other constructors. - -```dart -Filter.raw(value: { - 'members': [ - ..._selectedUsers.map((e) => e.id), - chatState.currentUser!.id, - ], - 'distinct': true, -}); -``` - -#### Filter.custom - -The 'custom' filter is used to create a custom filter in case it does not exists or it's not been added to the SDK yet. -Note that the filter must be supported by the Stream backend in order to work. - -```dart -Filter.custom( - operator: '\$max', - value: 10, -) -``` - -### Group Queries - -#### Filter.and - -The 'and' operator combines multiple queries. - -```dart -final filter = Filter.and([ - Filter.equal('type', 'messaging'), - Filter.in_('members', [user.id]) -]) -``` - -#### Filter.or - -Combines the provided filters and matches the values matched by at least one of the filters. - -```dart -final filter = Filter.or([ - Filter.in_('bannedUsers', [user.id]), - Filter.in_('shadowBannedUsers', [user.id]) -]) -``` - -#### Filter.nor - -Combines the provided filters and matches the values not matched by all the filters. - -```dart -final filter = Filter.nor([ - Filter.in_('bannedUsers', [user.id]), - Filter.in_('shadowBannedUsers', [user.id]) -]) -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/02-adding_local_data_persistence.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/02-adding_local_data_persistence.mdx deleted file mode 100644 index 3943b1f972..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/02-adding_local_data_persistence.mdx +++ /dev/null @@ -1,75 +0,0 @@ ---- -id: adding_local_data_persistence -title: Offline Support ---- - -Adding Local Data Persistence for Offline Support - -### Introduction - -Most messaging apps need to work regardless of whether the app is currently connected to the internet. -Local data persistence stores the fetched data from the backend on a local SQLite database using the -moor package in Flutter. All packages in the SDK can use local data persistence to store messages -across multiple platforms. - -### Implementation - -To add data persistence you can extend the class ChatPersistenceClient and pass an instance to the StreamChatClient. - -```dart -class CustomChatPersistentClient extends ChatPersistenceClient { -... -} - -final client = StreamChatClient( - apiKey ?? kDefaultStreamApiKey, - logLevel: Level.INFO, -)..chatPersistenceClient = CustomChatPersistentClient(); -``` - -We provide an official persistent client in the [`stream_chat_persistence`](https://pub.dev/packages/stream_chat_persistence) -package that works using the library [moor](https://moor.simonbinder.eu), an SQLite ORM. - -Add this to your package's `pubspec.yaml` file, using the latest version. - -```yaml -dependencies: - stream_chat_persistence: ^latest_version -``` - -You should then run `flutter packages get` - -The usage is pretty simple. - -1. Create a new instance of `StreamChatPersistenceClient` providing `logLevel` and `connectionMode` - -```dart -final chatPersistentClient = StreamChatPersistenceClient( - logLevel: Level.INFO, - connectionMode: ConnectionMode.background, -); -``` - -2. Pass the instance to the official `StreamChatClient` - -```dart - final client = StreamChatClient( - apiKey ?? kDefaultStreamApiKey, - logLevel: Level.INFO, - )..chatPersistenceClient = chatPersistentClient; -``` - -And you are ready to go... - -Note that passing `ConnectionMode.background` the database uses a background isolate to unblock the main thread. -The `StreamChatClient` uses the `chatPersistentClient` to synchronize the database with the newest -information every time it receives new data about channels/messages/users. - -### Multi-user - -The DB file is named after the `userId`, so if you instantiate a client using a different `userId` you will use a different database. -Calling `client.disconnectUser(flushChatPersistence: true)` flushes all current database data. - -### Updating/deleting/sending a message while offline - -The information about the action is saved in offline storage. When the client returns online, everything is retried. diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/03-user_token_generation_with_firebase_auth.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/03-user_token_generation_with_firebase_auth.mdx deleted file mode 100644 index 4292f7fb09..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/03-user_token_generation_with_firebase_auth.mdx +++ /dev/null @@ -1,454 +0,0 @@ ---- -id: token_generation_with_firebase -title: Authentication ---- - -Securely generate Stream Chat user tokens using Firebase Authentication and Cloud Functions. - -:::note -This guide assumes that you are familiar with Firebase Authentication and Cloud Functions for Flutter and using the Flutter Stream Chat SDK. -::: - -### Introduction - -In this guide, you'll explore how you can use Firebase Auth as an authentication provider and create Firebase Cloud functions to securely -generate Stream Chat user tokens. - -You will use Stream's [NodeJS client](https://getstream.io/chat/docs/node/?language=javascript) for Stream account creation and -token generation, and [Flutter Cloud Functions for Firebase](https://firebase.google.com/docs/functions/callable?gen=2nd#dart) to invoke the cloud functions -from your Flutter app. - -Stream supports several different [backend clients](https://getstream.io/chat/sdk/#backend-clients) to integrate with your server. This guide only shows an easy way to integrate Stream Chat authentication using Firebase and Flutter. - -### Flutter Firebase - -See the [Flutter Firebase getting started](https://firebase.google.com/docs/flutter/setup) docs for setup and installation instructions. - -You will also need to add the [Flutter Firebase Authentication](https://firebase.google.com/docs/auth/flutter/start), and [Flutter Firebase Cloud Functions](https://firebase.google.com/docs/functions/callable?gen=2nd#dart) packages to your app. Depending on the platform that you target, there may be specific configurations that you need to do. - -#### Starting Code - -The following code shows a basic application with **FirebaseAuth** and **FirebaseFunctions**. - -You will extend this later to execute cloud functions. - -```dart -import 'package:cloud_functions/cloud_functions.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:firebase_auth/firebase_auth.dart' as firebase_auth; -import 'package:flutter/material.dart'; -import 'dart:async'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - await Firebase.initializeApp(); - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: Scaffold( - body: Auth(), - ), - ); - } -} - -class Auth extends StatefulWidget { - const Auth({super.key}); - - @override - _AuthState createState() => _AuthState(); -} - -class _AuthState extends State { - late firebase_auth.FirebaseAuth auth; - late FirebaseFunctions functions; - - @override - void initState() { - super.initState(); - auth = firebase_auth.FirebaseAuth.instance; - functions = FirebaseFunctions.instance; - } - - final email = 'test@getstream.io'; - final password = 'password'; - - Future createAccount() async { - // Create Firebase account - await auth.createUserWithEmailAndPassword(email: email, password: password); - print('Firebase account created'); - } - - Future signIn() async { - // Sign in with Firebase - await auth.signInWithEmailAndPassword(email: email, password: password); - print('Firebase signed in'); - } - - Future signOut() async { - // Revoke Stream chat token. - final callable = functions.httpsCallable('revokeStreamUserToken'); - await callable(); - print('Stream user token revoked'); - } - - @override - Widget build(BuildContext context) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - AuthenticationState( - streamUser: auth.authStateChanges().map( - (firebaseUser) => firebaseUser != null - ? User( - id: firebaseUser.uid, - // Map other user fields here - ) - : null, - ), - ), - ElevatedButton( - onPressed: createAccount, - child: const Text('Create account'), - ), - ElevatedButton( - onPressed: signIn, - child: const Text('Sign in'), - ), - ElevatedButton( - onPressed: signOut, - child: const Text('Sign out'), - ), - ], - ), - ); - } -} - -class AuthenticationState extends StatelessWidget { - const AuthenticationState({ - super.key, - required this.streamUser, - }); - - final Stream streamUser; - - @override - Widget build(BuildContext context) { - return StreamBuilder( - stream: streamUser, - builder: (context, snapshot) { - if (snapshot.hasData) { - return (snapshot.data != null) - ? const Text('Authenticated') - : const Text('Not Authenticated'); - } - return const Text('Not Authenticated'); - }, - ); - } -} - -``` - -Running the above will give this: - -![](../assets/authentication_demo_app.jpg) - -The `Auth` widget handles all of the authentication logic. It initializes a `FirebaseAuth.instance` and uses that -in the `createAccount`, `signIn` and `signOut` methods. There is a button to invoke each of these methods. - -The `FirebaseFunctions.instance` will be used later in this guide. - -The `AuthenticationState`` widget listens to `auth.authStateChanges()` (mapped to Stream's `User`) -to display a message indicating if a user is authenticated. - -### Firebase Cloud Functions - -Firebase Cloud Functions allows you to extend Firebase with custom operations that an event can trigger: -- **Internal event**: For example, when creating a new Firebase account this is automatically triggered. -- **External event**: For example, directly calling a cloud function from your Flutter application. - -To set up your local environment to deploy cloud functions, please see the -[Cloud Functions getting started](https://firebase.google.com/docs/flutter/setup) docs. - -After initializing your project with cloud functions, you should have a **functions** folder in your project, including a `package.json` file. - -There should be two dependencies already added, **firebase-admin** and **firebase-functions**. You will also need to add the **stream-chat** dependency. - -Navigate to the **functions** folder and run `npm install stream-chat --save-prod`. - -This will install the node module and add it as a dependency to `package.json`. - -Now open `index.js` and add the following (this is the complete example): - -```js -const StreamChat = require('stream-chat').StreamChat; -const functions = require("firebase-functions"); -const admin = require("firebase-admin"); - -admin.initializeApp(); - -const serverClient = StreamChat.getInstance(functions.config().stream.key, functions.config().stream.secret); - - -// When a user is deleted from Firebase their associated Stream account is also deleted. -exports.deleteStreamUser = functions.auth.user().onDelete((user, context) => { - return serverClient.deleteUser(user.uid); -}); - -// Create a Stream user and return auth token. -exports.createStreamUserAndGetToken = functions.https.onCall(async (data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - // Create user using the serverClient. - await serverClient.upsertUser({ - id: context.auth.uid, - name: context.auth.token.name, - email: context.auth.token.email, - image: context.auth.token.image, - }); - - /// Create and return user auth token. - return serverClient.createToken(context.auth.uid); - } catch (err) { - console.error(`Unable to create user with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not create Stream user"); - } - } -}); - -// Get Stream user token. -exports.getStreamUserToken = functions.https.onCall((data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - return serverClient.createToken(context.auth.uid); - } catch (err) { - console.error(`Unable to get user token with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not get Stream user"); - } - } -}); - -// Revoke the authenticated user's Stream chat token. -exports.revokeStreamUserToken = functions.https.onCall((data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - return serverClient.revokeUserToken(context.auth.uid); - } catch (err) { - console.error(`Unable to revoke user token with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not get Stream user"); - } - } -}); - -``` - -First, you import the necessary packages and call `admin.initializeApp();` to set up Firebase cloud functions. - -Next, you initialize the **StreamChat** server client by calling `StreamChat.getInstance`. This function requires your Stream app's -**token** and **secret**. You can get this from the Stream Dashboard for your app. - -Set these values as environment data on Firebase Functions. - -```bash - firebase functions:config:set stream.key="app-key" stream.secret="app-secret" -``` - -*Replace **app-key** and **app-secret** with the values for your Stream app.* - -This creates an object of **stream** with properties **key** and **secret**. To access this environment -data use `functions.config().stream.key` and `functions.config().stream.secret`. - -See the [Firebase environment configuration](https://firebase.google.com/docs/functions/config-env) -documentation for additional information. - -To deploy these functions to Firebase, run: - -```bash -firebase deploy --only functions -``` - -### Create a Stream User and Get the User's Token - -In the `createStreamUserAndGetToken` cloud function you create an `onCall` HTTPS handler, which exposes -a cloud function that can be invoked from your Flutter app. - -```js -// Create a Stream user and return auth token. -exports.createStreamUserAndGetToken = functions.https.onCall(async (data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - // Create user using the serverClient. - await serverClient.upsertUser({ - id: context.auth.uid, - name: context.auth.token.name, - email: context.auth.token.email, - image: context.auth.token.image, - }); - - /// Create and return user auth token. - return serverClient.createToken(context.auth.uid); - } catch (err) { - console.error(`Unable to create user with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not create Stream user"); - } - } -}); -``` - -This function first does a check to see that the client that calls it is authenticated, -by ensuring that `context.auth` is not null. If it is null, then it throws an `HttpsError` with a descriptive -message. This error can be caught in your Flutter application. - -If the caller is authenticated the function proceeds to use the `serverClient` to create a new Stream Chat -user by calling the `upsertUser` method and passing in some user data. It uses the authenticated caller's **`uid`** as an **id**. - -After the user is created it generates a token for that user. This token is then returned to the caller. - -To call this from Flutter, you will need to use the `cloud_functions` package. - -Update the **`createAccount`** method in your Flutter code to the following: - -```dart -Future createAccount() async { - // Create Firebase account - await auth.createUserWithEmailAndPassword(email: email, password: password); - print('Firebase account created'); - - // Create Stream user and get token - final callable = functions.httpsCallable('createStreamUserAndGetToken'); - final results = await callable(); - print('Stream account created, token: ${results.data}'); -} -``` - -Calling this method will do the following: -1. Create a new Firebase User and authenticate that user. -2. Call the `createStreamUserAndGetToken` cloud function and get the Stream user token for the authenticated user. - -As you can see, calling a cloud function is easy and will also send all the necessary user authentication information (such as the UID) -in the request. - -Once you have the Stream user token, you can authenticate your Stream Chat user as you normally would. - -Please see our [initialization documentation](https://getstream.io/chat/docs/flutter-dart/init_and_users/?language=dart) for more information. - -As you can see below, the User ID matches on both Firebase's and Stream's user database. - -##### Firebase Authentication Database - -![Firebase Auth Database with new user created](../assets/firebase_authentication_dashboard.jpg) - -##### Stream Chat User Database - -![Stream chat user database new account created](../assets/stream_chat_user_database.jpg) - - -### Get the Stream User Token - -The `getStreamUserToken` cloud function is very similar to the `createStreamUserAndGetToken` function. The only difference is -that it only creates a user token and does not create a new user account on Stream. - -Update the **`signIn`** method in your Flutter code to the following: - -```dart -Future signIn() async { - // Sign in with Firebase - await auth.signInWithEmailAndPassword(email: email, password: password); - print('Firebase signed in'); - - // Get Stream user token - final callable = functions.httpsCallable('getStreamUserToken'); - final results = await callable(); - print('Stream user token retrieved: ${results.data}'); -} -``` - -Calling this method will do the following: -1. Sign in using Firebase Auth. -2. Call the `getStreamUserToken` cloud function to get a Stream user token. - -:::note -The user needs to be authenticated to call this cloud function. Otherwise, the function will throw -the **failed-precondition** error that you specified. -::: - -### Revoke Stream User Token - -You may also want to revoke the Stream user token if you sign out from Firebase. - -Update the `signOut` method in your Flutter code to the following: - -```dart -Future signOut() async { - // Revoke Stream user token. - final callable = functions.httpsCallable('revokeStreamUserToken'); - await callable(); - print('Stream user token revoked'); - - // Sign out Firebase. - await auth.signOut(); - print('Firebase signed out'); -} -``` -:::note -Call the cloud function before signing out from Firebase. -::: - -### Delete Stream User - -When deleting a Firebase user account, it would make sense also to delete the -associated Stream user account. - -The cloud function looks like this: - -```js -// When a user is deleted from Firebase their associated Stream account is also deleted. -exports.deleteStreamUser = functions.auth.user().onDelete((user, context) => { - return serverClient.deleteUser(user.uid); -}); -``` - -In this function, you are listening to delete events on Firebase auth. When an account is deleted, this function will be triggered, and you can get the -user's **`uid`** and call the `deleteUser` method on the `serverClient`. - -This is not an external cloud function; it can only be triggered when an -account is deleted. - -### Conclusion - -In this guide, you have seen how to securely create Stream Chat tokens using -Firebase Authentication and Cloud Functions. - -The principles shown in this guide can be applied to your preferred authentication -provider and cloud architecture of choice. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/04-adding_localization.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/04-adding_localization.mdx deleted file mode 100644 index 4f9456930e..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/04-adding_localization.mdx +++ /dev/null @@ -1,203 +0,0 @@ ---- -id: adding_localization -title: Localization ---- - -Adding Localization (l10n) / Internationalization (i18n) To UI Widgets - -### Introduction - -We have a dedicated package for adding localization to our UI widgets. It's called `stream_chat_localizations` and you can find it [here](https://pub.dev/packages/stream_chat_localizations). - -![](../assets/localization_support.jpg) - -## What is Localization? - -If you deploy your app to users who speak another language, you'll need to internationalize (localize) it. That means you need to write the app in a way that makes it possible to localize values like text and layouts for each language or locale that the app supports. For more information, see the [Flutter documentation](https://flutter.dev/docs/development/accessibility-and-localization/internationalization). - -What this package allows you to do is to provide localized strings for the Stream chat widgets. For example, depending on the application locale, the Stream Chat widgets will display the appropriate language. The locale will be set automatically, based on system preferences, or you could set it programmatically in your app. The package supports several different languages, with more to be added. The package allows you to override any supported language or add a new language that isn't supported. - -:::note -If you want to translate messages, or enable automatic translation, please see the [Translation documentation](https://getstream.io/chat/docs/flutter-dart/translation/?language=dart). -::: - -### Supported languages - -At the moment we support the following languages: -- [English](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart) -- [Hindi](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart) -- [Italian](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart) -- [French](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart) -- [Spanish](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart) -- [Japanese](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart) -- [Korean](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart) -- [Portuguese](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_pt.dart) -- [German](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_de.dart) -- [Norwegian](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_no.dart) -More languages will be added in the future. Feel free to [contribute](https://github.com/GetStream/stream-chat-flutter/blob/master/CONTRIBUTING.md) to add more languages. - -### Add dependency - -Add this to your package's `pubspec.yaml` file, use the latest version [![Pub](https://img.shields.io/pub/v/stream_chat_localizations.svg)](https://pub.dartlang.org/packages/stream_chat_localizations) -```yaml -dependencies: - stream_chat_localizations: ^latest_version -``` - -Then run `flutter packages get` - -### Usage - -Generally, Flutter and the Stream Chat SDK will use the system locale of the user's device, if that locale is supported (see below). If the locale is not supported we will default to `en` (however it's always possible to [customize that](#changing-the-default-language)). -Make sure to read more about localization in the [official Flutter docs](https://flutter.dev/docs/development/accessibility-and-localization/internationalization). - -```dart -import 'package:flutter/material.dart'; -import 'package:stream_chat_localizations/stream_chat_localizations.dart'; - -void main() { - WidgetsFlutterBinding.ensureInitialized(); - runApp(MyApp()); -} - -class MyApp extends StatelessWidget { - - // Setup client and channel code here - ... - - @override - Widget build(BuildContext context) { - return MaterialApp( - // Add all the supported locales - supportedLocales: const [ - Locale('en'), - Locale('hi'), - Locale('fr'), - Locale('it'), - Locale('es'), - Locale('ja'), - Locale('ko'), - Locale('pt'), - Locale('de'), - Locale('no'), - ], - // Add GlobalStreamChatLocalizations.delegates - localizationsDelegates: GlobalStreamChatLocalizations.delegates, - builder: (context, widget) => StreamChat( - client: client, - child: widget, - ), - home: StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ); - } -} -``` - -## Setting a language -The application language can be changed through system preferences or programmatically. - -### System Preferences -The application locale can be changed by changing the language for your device or emulator within the device's system preferences. - -[iOS change language](https://support.apple.com/en-us/HT204031) - -[Android change language](https://support.google.com/websearch/answer/3333234?co=GENIE.Platform%3DAndroid&hl=en) - -Note that the language needs to be supported in your application to work. - -### Programmatically -You can also set the locale programmatically in your Flutter application without changing the device's language. - -```dart -return MaterialApp( - ... - locale: const Locale('fr'), - ... -); -``` - -There are many ways that this can be set for additional control. For information and examples, see this [Stack Overflow post](https://stackoverflow.com/questions/49441212/flutter-multi-lingual-application-how-to-override-the-locale). - -### Adding a new language - -To add a new language, create a new class extending `GlobalStreamChatLocalizations` and create a delegate for it, adding it to the `delegates` array. - -Check out [this example](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/example/lib/add_new_lang.dart) to see how to add a new language. - -### Override existing languages - -To override an existing language, create a new class extending that particular language class and create a delegate for it, adding it to the `delegates` array. - -Check out [this example](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/example/lib/override_lang.dart) to see how to override an existing language. - -### Changing the default language - -To change the default language you can use the `MaterialApp.localeListResolutionCallback` property. -Here is an example of how that would look like: - -```dart - MaterialApp( - theme: ThemeData.light(), - darkTheme: ThemeData.dark(), - // Add all the supported locales - supportedLocales: const [ - Locale('en'), - Locale('hi'), - Locale('fr'), - Locale('it'), - Locale('es'), - Locale('ja'), - Locale('ko'), - ], - // locales are the locales of the device - // supportedLocales are the app supported locales - localeListResolutionCallback: (locales, supportedLocales) { - // We map the supported locales to language codes - // note that this is completely optional and this logic can be changed as you like - final supportedLanguageCodes = - supportedLocales.map((e) => e.languageCode); - if (locales != null) { - // we iterate over the locales and find the first one that is supported - for (final locale in locales) { - if (supportedLanguageCodes.contains(locale.languageCode)) { - return locale; - } - } - } - - // if we didn't find a supported language, we return the Italian language - return const Locale('it'); - }, - // Add GlobalStreamChatLocalizations.delegates - localizationsDelegates: GlobalStreamChatLocalizations.delegates, - ... - -``` - -In this case, we're using Italian as the default language. - -### ⚠️ Note on **iOS** - -For translation to work on **iOS** you need to add supported locales to -`ios/Runner/Info.plist` as described [here](https://flutter.dev/docs/development/accessibility-and-localization/internationalization#specifying-supportedlocales). - -Example: - -```xml -CFBundleLocalizations - - en - hi - fr - it - es - ja - ko - pt - de - no - -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/05-push-notifications/_category_.json b/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/05-push-notifications/_category_.json deleted file mode 100644 index 26b1d64ec7..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/05-push-notifications/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Push Notifications" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/05-push-notifications/adding_push_notifications.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/05-push-notifications/adding_push_notifications.mdx deleted file mode 100644 index 6859251ed3..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/05-push-notifications/adding_push_notifications.mdx +++ /dev/null @@ -1,262 +0,0 @@ ---- -id: adding_push_notifications -title: Legacy ---- - -Adding Push Notifications To Your Application - -:::note -Version 1 (legacy) of push notifications won't be removed immediately but there won't be any new features. That's why new applications are highly recommended to use version 2 from the beginning to leverage upcoming new features. -::: - -### Introduction - -Push notifications are a core part of the experience for a messaging app. Users often need to be notified -of new messages and old notifications sometimes need to be updated silently as well. - -This guide details how to add push notifications to your app. - -Make sure to check [this section](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart) of the docs to read about the push delivery logic. - -### Setup FCM - -To integrate push notifications in your Flutter app you need to use the package [`firebase_messaging`](https://pub.dev/packages/firebase_messaging). - - -Follow the [Firebase documentation](https://firebase.flutter.dev/docs/messaging/overview/) to know how to set up the plugin for both Android and iOS. - - -Once that's done FCM should be able to send push notifications to your devices. - -### Integration with Stream - -#### Step 1 - -From the [Firebase Console](https://console.firebase.google.com/), select the project your app belongs to. - -#### Step 2 - -Click on the gear icon next to `Project Overview` and navigate to **Project settings** - -![](../../assets/firebase_project_settings.jpeg) - -#### Step 3 - -Navigate to the `Cloud Messaging` tab - -#### Step 4 - -Under `Project Credentials`, locate the `Server key` and copy it - -![](../../assets/server_key.png) - -#### Step 5 - -Upload the `Server Key` in your chat dashboard - -![](../../assets/dashboard_firebase_enable.jpeg) - -![](../../assets/dashboard_firebase_key.jpeg) - - -:::note -We are setting up the Android section, but this will work for both Android and iOS if you're using Firebase for both of them. -::: - -#### Step 6 - -Save your push notification settings changes - -![](../../assets/dashboard_save_changes.jpeg) - -**OR** - -Upload the `Server Key` via API call using a backend SDK - -```js -await client.updateAppSettings({ - firebase_config: { - server_key: 'server_key', - notification_template: `{"message":{"notification":{"title":"New messages","body":"You have {{ unread_count }} new message(s) from {{ sender.name }}"},"android":{"ttl":"86400s","notification":{"click_action":"OPEN_ACTIVITY_1"}}}}`, - data_template: `{"sender":"{{ sender.id }}","channel":{"type": "{{ channel.type }}","id":"{{ channel.id }}"},"message":"{{ message.id }}"}` - }, -}); -``` - -### Registering a device at Stream Backend - -Once you configure Firebase server key and set it up on Stream dashboard a device that is supposed to receive push notifications needs to be registered at Stream backend. This is usually done by listening for Firebase device token updates and passing them to the backend as follows: - -```dart -firebaseMessaging.onTokenRefresh.listen((token) { - client.addDevice(token, PushProvider.firebase); -}); -``` - -### Possible issues - - -We only send push notifications when the user doesn't have any active web socket connection (which is established when you call `client.connectUser`). If you set the [onBackgroundEventReceived](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/onBackgroundEventReceived.html) property of the StreamChat widget, when your app goes to background, your device will keep the WS connection alive for 1 minute, and so within this period, you won't receive any push notification. - -Make sure to read the [general push docs](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart) in order to avoid known gotchas that may make your relationship with notifications go bad 😢 - -### Testing if Push Notifications are Setup Correctly - -If you're not sure if you've set up push notifications correctly (for example you don't always receive them, they work unreliably), you can follow these steps to make sure your configuration is correct and working: - -1. Clone our repository for push testing git clone git@github.com:GetStream/chat-push-test.git - -2. `cd flutter` - -3. In folder run `flutter pub get` - -4. Input your API key and secret in `lib/main.dart` - -5. Change the bundle identifier/application ID and development team/user so you can run the app in your device (**do not** run on iOS simulator, Android emulator is fine) - -6. Add your `google-services.json/GoogleService-Info.plist` - -7. Run the app - -8. Accept push notification permission (iOS only) - -9. Tap on `Device ID` and copy it - -10. Send the app to background - -11. After configuring [stream-cli](https://github.com/GetStream/stream-cli) paste the following command on command line using your user ID - -```shell -stream chat:push:test -u -``` - -You should get a test push notification - -### App in the background but still connected - -The [StreamChat](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat-class.html) widget lets you define a [onBackgroundEventReceived](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/onBackgroundEventReceived.html) handler in order to handle events while the app is in the background, but the client is still connected. - -This is useful because it lets you keep the connection alive in cases in which the app goes in the background just for some seconds (for example multitasking, picking pictures from the gallery...) - -You can even customize the [backgroundKeepAlive](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/backgroundKeepAlive.html) duration. - -In order to show notifications in such a case we suggest using the package [`flutter_local_notifications`](https://pub.dev/packages/flutter_local_notifications); follow the package guide to successfully set up the plugin. - -Once that's done you should set the [onBackgroundEventReceived](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/onBackgroundEventReceived.html); here is an example: - -```dart -... -StreamChat( - client: client, - onBackgroundEventReceived: (e) { - final currentUserId = client.state.user.id; - if (![ - EventType.messageNew, - EventType.notificationMessageNew, - ].contains(event.type) || - event.user.id == currentUserId) { - return; - } - if (event.message == null) return; - final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); - final initializationSettingsAndroid = - AndroidInitializationSettings('launch_background'); - final initializationSettingsIOS = IOSInitializationSettings(); - final initializationSettings = InitializationSettings( - android: initializationSettingsAndroid, - iOS: initializationSettingsIOS, - ); - await flutterLocalNotificationsPlugin.initialize(initializationSettings); - await flutterLocalNotificationsPlugin.show( - event.message.id.hashCode, - event.message.user.name, - event.message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'message channel', - 'Message channel', - 'Channel used for showing messages', - priority: Priority.high, - importance: Importance.high, - ), - iOS: IOSNotificationDetails(), - ), - ); - }, - child: .... -); -... -``` - -As you can see we generate a local notification whenever a message.new or notification.message_new event is received. - -### Foreground notifications - -Sometimes you may want to show a notification when the app is in the foreground. -For example, when you're in a channel and you receive a new message from someone in another channel. - -For this scenario, you can also use the `flutter_local_notifications` package to show a notification. - -You need to listen for new events using `StreamChatClient.on` and handle them accordingly. - -Here we're checking if the event is a `message.new` or `notification.message_new` event, and if the message is from a different user than the current user. In that case we'll show a notification. - -```dart -client.on( - EventType.messageNew, - EventType.notificationMessageNew, -).listen((event) { - if (event.message?.user?.id == client.state.currentUser?.id) { - return; - } - showLocalNotification(event, client.state.currentUser!.id, context); -}); -``` - -:::note -You should also check that the channel of the message is different than the channel in the foreground. -How you do this depends on your app infrastructure and how you handle navigation. -Take a look at the [Stream Chat v1 sample app](https://github.com/GetStream/flutter-samples/blob/main/packages/stream_chat_v1/lib/home_page.dart#L11) to see how we're doing it over there. -::: - -### Saving notification messages to the offline storage - -You may want to save received messages when you receive them via a notification so that later on when you open the app they're already there. - -To do this we need to update the push notification data payload at Stream Dashboard and clear the notification one: - -```json -{ - "message_id": "{{ message.id }}", - "channel_id": "{{ channel.id }}", - "channel_type": "{{ channel.type }}" -} -``` - -Then we need to integrate the package [`stream_chat_persistence`](https://pub.dev/packages/stream_chat_persistence) in our app that exports a persistence client, learn [here](https://pub.dev/packages/stream_chat_persistence#usage) how to set it up. - -Then during the call `firebaseMessaging.configure(...)` we need to set the `onBackgroundMessage` parameter using a TOP-LEVEL or STATIC function to handle background messages; here is an example: - -```dart -Future myBackgroundMessageHandler(message) async { - if (message.containsKey('data')) { - final data = message['data']; - final messageId = data['message_id']; - final channelId = data['channel_id']; - final channelType = data['channel_type']; - final cid = '$channelType:$channelId'; - - final client = StreamChatClient(apiKey); - final persistenceClient = StreamChatPersistenceClient(); - await persistenceClient.connect(userId); - - final message = await client.getMessage(messageId).then((res) => res.message); - - await persistenceClient.updateMessages(cid, [message]); - persistenceClient.disconnect(); - - /// This can be done using the package flutter_local_notifications as we did before 👆 - _showLocalNotification(); - } -} -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/05-push-notifications/adding_push_notifications_v2.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/05-push-notifications/adding_push_notifications_v2.mdx deleted file mode 100644 index 81ee284ad5..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/05-push-notifications/adding_push_notifications_v2.mdx +++ /dev/null @@ -1,355 +0,0 @@ ---- -id: adding_push_notifications_v2 -title: Push Notifications ---- - -Adding Push Notifications (V2) To Your Application - -### Introduction - -This guide details how to add push notifications to your app. - -Push notifications are a core part of the experience for a messaging app. Users often need to be notified -of new messages and old notifications sometimes need to be updated silently. - -Stream Chat sends push notification to channel members that have at least one registered device. -Push notifications are only sent for new messages and not for other events. -You can use [Webhooks](https://getstream.io/chat/docs/android/webhooks_overview/) to send push notifications on other types of events. - -You can read more about Stream’s [push delivery logic](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart#push-delivery-rules). - -To receive push notifications from Stream Chat, 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). - -### Push Delivery Rules - -Push message delivery behaves according to these rules: - -- Push notifications are sent only for new messages. -- Only channel members receive push messages. -- Members receive push notifications regardless of their online status. -- Replies inside a [thread](https://getstream.io/chat/docs/threads/) are only sent to users that are part of that thread: - - They posted at least one message - - They were mentioned -- Messages from muted users are not sent. -- Messages from muted channels are not sent. -- Messages are sent to all registered devices for a user (up to 25). -- The message doesn't contain the flag `skip_push` as true. -- `push_notifications` is enabled (default) on the channel type for message is sent. - -:::caution - -Push notifications require membership. Watching a channel isn't enough. - -::: - -### Setup FCM - -To integrate push notifications in your Flutter app, you need to use the package [`firebase_messaging`](https://pub.dev/packages/firebase_messaging). - -Follow the [Flutter Firebase documentation](https://firebase.flutter.dev/docs/messaging/overview/) to set up the plugin for Android and iOS. -Additional setup and instructions can be found [here](https://firebase.google.com/docs/cloud-messaging/flutter/client). Be sure to read this documentation to understand Firebase messaging functionality. - -Once that's done, FCM should be able to send push notifications to your devices. - -### Integration With Stream - -#### Step 1 - Get the Firebase Credentials - -These credentials are the [private key file](https://firebase.google.com/docs/admin/setup#:~:text=To%20generate%20a%20private%20key%20file%20for%20your%20service%20account%3A) 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 can upload your Firebase credentials using either the dashboard or the app settings API (available only in backend SDKs). - -##### Using the Stream Dashboard - -1. Go to the **Chat Overview** page on Stream Dashboard. - -![](../../assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png) - -2. Enable **Firebase Notification** toggle on **Chat Overview**. - -![](../../assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png) - -3. Enter your Firebase Credentials and press `"Save"`. - -##### Using the API - -You can also enable Firebase notifications and upload the Firebase credentials using one of our server SDKs. - -For example, using the Stream JavaScript SDK: - -```js -const client = StreamChat.getInstance('api_key', 'api_secret'); -client.updateAppSettings({ - push_config: { - version: 'v2' - }, - firebase_config: { - credentials_json: fs.readFileSync( - './firebase-credentials.json', - 'utf-8', - ), - }); -``` - -### Registering a Device With Stream Backend - -Once you configure a Firebase server key 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. This is usually done by listening for Firebase device token updates and passing them to the backend as follows: - -```dart -firebaseMessaging.onTokenRefresh.listen((token) { - client.addDevice(token, PushProvider.firebase); -}); -``` - -Push Notifications v2 also supports specifying a name for the push device tokens you register. By setting the optional `pushProviderName` parameter in the `addDevice` call, you can support different configurations between the device and the `PushProvider`. - -```dart -firebaseMessaging.onTokenRefresh.listen((token) { - client.addDevice(token, PushProvider.firebase, pushProviderName: 'my-custom-config'); -}); -``` - -### Receiving Notifications - -Push notifications behave differently depending on whether you are using iOS or Android. -See [here](https://firebase.flutter.dev/docs/messaging/usage#message-types) to understand the difference between **notification** and **data** payloads. - -#### iOS - -On iOS, we send both a **notification** and a **data** payload. -This means you don't need to do anything special to get the notification to show up. However, you might want to handle the data payload to perform some logic when the user taps on the notification. - -To update the template, you can use a backend SDK. -For example, using the Stream JavaScript SDK: - -```js -const client = StreamChat.getInstance(‘api_key’, ‘api_secret’); -const apn_template = `{ - "aps": { - "alert": { - "title": "New message from {{ sender.name }}", - "body": "{{ truncate message.text 2000 }}" - }, - "mutable-content": 1, - "category": "stream.chat" - }, - "stream": { - "sender": "stream.chat", - "type": "message.new", - "version": "v2", - "id": "{{ message.id }}", - "cid": "{{ channel.cid }}" - } -}`; - -client.updateAppSettings({ - firebase_config: { - apn_template, - }); -``` - -#### Android - -On Android, we send only a **data** payload. This gives you more flexibility and lets you decide what to do with the notification. - -For example, you can listen and generate a notification from them. - -The code below demonstrates how to generate a notification when a **data-only** message is received and the app is in the background. - -There are a few things to keep in mind about your background message handler: - -1. It must not be an anonymous function. -2. It must be a top-level function (not a class method which requires initialization). -3. It must be annotated with @pragma('vm:entry-point') right above the function declaration (otherwise it may be removed during tree shaking for release mode). - -For additional information on background messages, please see the [Firebase documentation](https://firebase.google.com/docs/cloud-messaging/flutter/receive#background_messages). - -```dart -@pragma('vm:entry-point') -Future onBackgroundMessage(RemoteMessage message) async { - final chatClient = StreamChatClient(apiKey); - - chatClient.connectUser( - User(id: userId), - userToken, - connectWebSocket: false, - ); - - handleNotification(message, chatClient); -} - -void handleNotification( - RemoteMessage message, - StreamChatClient chatClient, -) async { - - final data = message.data; - - if (data['type'] == 'message.new') { - final flutterLocalNotificationsPlugin = await setupLocalNotifications(); - final messageId = data['id']; - final response = await chatClient.getMessage(messageId); - - flutterLocalNotificationsPlugin.show( - 1, - 'New message from ${response.message.user!.name} in ${response.channel!.name}', - response.message.text, - const NotificationDetails( - android: AndroidNotificationDetails( - 'new_message', - 'New message notifications channel', - )), - ); - } -} - -FirebaseMessaging.onBackgroundMessage(onBackgroundMessage); -``` - -In the above example, you get the message details using the `getMessage` method, and then you use the [`flutter_local_notifications`](https://pub.dev/packages/flutter_local_notifications) package to show the actual notification. - -##### Using a Template on Android - -Adding a **notification** payload to Android notifications is still possible. -You can do so by adding a template using a backend SDK. -For example, using the Stream JavaScript SDK: - -```js -const client = StreamChat.getInstance(‘api_key’, ‘api_secret’); -const notification_template = ` -{ - "title": "{{ sender.name }} @ {{ channel.name }}", - "body": "{{ message.text }}", - "click_action": "OPEN_ACTIVITY_1", - "sound": "default" -}`; - -client.updateAppSettings({ - firebase_config: { - notification_template, - }); -``` - -### Possible Issues - -Make sure to read the [general push notification docs](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart) to prevent common issues with notifications 😢. - -### Testing if Push Notifications are Setup Correctly - -If you're not sure whether you've set up push notifications correctly, for example, you don't always receive them, or they don’t work reliably, then you can follow these steps to make sure your configuration is correct and working: - -1. Clone our repository for push testing: `git clone git@github.com:GetStream/chat-push-test.git` -2. `cd chat-push-test/flutter` -3. In that folder run `flutter pub get` -4. Input your API key and secret in `lib/main.dart` -5. Change the bundle identifier/application ID and development team/user so you can run the app on your physical device.**Do not** run on an iOS simulator, as it will not work. Testing on an Android emulator is fine. -6. Add your `google-services.json/GoogleService-Info.plist` -7. Run the app -8. Accept push notification permission (iOS only) -9. Tap on `Device ID` and copy it -10. After configuring [stream-cli](https://github.com/GetStream/stream-cli), run the following command using your user ID: - -```shell -stream chat:push:test -u -``` - -You should get a test push notification 🥳 - -### Foreground Notifications - -You may want to show a notification when the app is in the foreground. -For example, when you're in a channel and receive a new message from someone in another channel. - -For this scenario, you can also use the `flutter_local_notifications` package to show a notification. - -You need to listen for new events using `FirebaseMessaging.onMessage.listen()` and handle them accordingly: - -```dart -FirebaseMessaging.onMessage.listen((message) async { - handleNotification( - message, - chatClient, - ); -}); -``` - -:::note -You should also check that the message's channel differs from the channel in the foreground. -How you do this depends on your app infrastructure and how you handle navigation. - -Take a look at the [Stream Chat v1 sample app](https://github.com/GetStream/flutter-samples/blob/main/packages/stream_chat_v1/lib/home_page.dart#L11) to see how we're doing it over there. -::: - -### Saving Notification Messages to the Offline Storage (Only Android) - -When the app is closed, you can save incoming messages when you receive them via a notification so that they're already there later when you open the app. - -To do this, you need to integrate the package [`stream_chat_persistence`](https://pub.dev/packages/stream_chat_persistence) that exports a persistence client. See [here](https://pub.dev/packages/stream_chat_persistence#usage) for information on how to set it up. - -Then calling `FirebaseMessaging.onBackgroundMessage(...)` you need to use a TOP-LEVEL or STATIC function to handle background messages. - -For additional information on background messages, please see the [Firebase documentation](https://firebase.google.com/docs/cloud-messaging/flutter/receive#background_messages). - -Here is an example: - -```dart -@pragma('vm:entry-point') -Future onBackgroundMessage(RemoteMessage message) async { - final chatClient = StreamChatClient(apiKey); - final persistenceClient = StreamChatPersistenceClient(); - - await persistenceClient.connect(userId); - - chatClient.connectUser( - User(id: userId), - userToken, - connectWebSocket: false, - ); - - handleNotification(message, chatClient); -} - -void handleNotification( - RemoteMessage message, - StreamChatClient chatClient, -) async { - final data = message.data; - if (data['type'] == 'message.new') { - final flutterLocalNotificationsPlugin = await setupLocalNotifications(); - final messageId = data['id']; - final cid = data['cid']; - final response = await chatClient.getMessage(messageId); - await persistenceClient.updateMessages(cid, [response.message]); - - persistenceClient.disconnect(); - - flutterLocalNotificationsPlugin.show( - 1, - 'New message from ${response.message.user.name} in ${response.channel.name}', - response.message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'new_message', - 'New message notifications channel', - )), - ); - } -} - -FirebaseMessaging.onBackgroundMessage(onBackgroundMessage); -``` diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/06-end_to_end_chat_encryption.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/06-end_to_end_chat_encryption.mdx deleted file mode 100644 index cf204cfc60..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/06-end_to_end_chat_encryption.mdx +++ /dev/null @@ -1,259 +0,0 @@ ---- -id: end_to_end_chat_encryption -title: Encryption ---- - -Adding End To End Encryption to your Chat App - -## Introduction - -When you communicate over a chat application with another person or group, -you may exchange sensitive information, like personally identifiable information, financial details, or passwords. -A chat application should use end-to-end encryption to ensure that users' data stays secure. - -:::note -Before you start, keep in mind that this guide is a basic example intended for educational purposes only. -If you want to implement end-to-end encryption in your production app, please consult a security professional first. -There’s a lot more to consider from a security perspective that isn’t covered here. -::: - -## What is End-to-End Encryption? - -End-to-end encryption (E2EE) is the process of securing a message from third parties so that only the sender and receiver can access the message. -E2EE provides security by storing the message in an encrypted form on the application's server or database. - -You can only access the message by decrypting and signing it using a known public key (distributed freely) -and a corresponding private key (only known by the owner). - -Each user in the application has their own public-private key pair. -Public keys are distributed publicly and encrypt the sender’s messages. -The receiver can only decrypt the sender’s message with the matching private key. - -Check out the diagram below for an example: - -![](../assets/end_to_end_encryption.png) - -## Setup - -### Dependencies - -Add the [`webcrypto`](https://pub.dev/packages/webcrypto) package in your `pubspec.yaml` file. - -```yaml -dependencies: - webcrypto: ^0.5.2 # latest version -``` - -### Generate Key Pair - -Write a function that generates a key pair using the **ECDH** algorithm and the **P-256** elliptic curve (**P-256** is well-supported and -offers the right balance of security and performance). - -The pair will consist of two keys: -- **PublicKey**: The key that is linked to a user to encrypt messages. -- **PrivateKey**: The key that is stored locally to decrypt messages. - -```dart -Future generateKeys() async { - final keyPair = await EcdhPrivateKey.generateKey(EllipticCurve.p256); - final publicKeyJwk = await keyPair.publicKey.exportJsonWebKey(); - final privateKeyJwk = await keyPair.privateKey.exportJsonWebKey(); - - return JsonWebKeyPair( - privateKey: json.encode(privateKeyJwk), - publicKey: json.encode(publicKeyJwk), - ); -} - -// Model class for storing keys -class JsonWebKeyPair { - const JsonWebKeyPair({ - required this.privateKey, - required this.publicKey, - }); - - final String privateKey; - final String publicKey; -} -``` - -### Generate a Cryptographic Key - -Next, create a symmetric **Cryptographic Key** using the keys generated in the previous step. -You will use those keys to encrypt and decrypt messages. - -```dart -// SendersJwk -> sender.privateKey -// ReceiverJwk -> receiver.publicKey -Future> deriveKey(String senderJwk, String receiverJwk) async { - // Sender's key - final senderPrivateKey = json.decode(senderJwk); - final senderEcdhKey = await EcdhPrivateKey.importJsonWebKey( - senderPrivateKey, - EllipticCurve.p256, - ); - - // Receiver's key - final receiverPublicKey = json.decode(receiverJwk); - final receiverEcdhKey = await EcdhPublicKey.importJsonWebKey( - receiverPublicKey, - EllipticCurve.p256, - ); - - // Generating CryptoKey - final derivedBits = await senderEcdhKey.deriveBits(256, receiverEcdhKey); - return derivedBits; -} -``` - -### Encrypting Messages - -Once you have generated the **Cryptographic Key**, you're ready to encrypt the message. -You can use the **AES-GCM** algorithm for its known security and performance balance and good browser availability. - -```dart -// The "iv" stands for initialization vector (IV). To ensure the encryption’s strength, -// each encryption process must use a random and distinct IV. -// It’s included in the message so that the decryption procedure can use it. -final Uint8List iv = Uint8List.fromList('Initialization Vector'.codeUnits); -``` - -```dart -Future encryptMessage(String message, List deriveKey) async { - // Importing cryptoKey - final aesGcmSecretKey = await AesGcmSecretKey.importRawKey(deriveKey); - - // Converting message into bytes - final messageBytes = Uint8List.fromList(message.codeUnits); - - // Encrypting the message - final encryptedMessageBytes = - await aesGcmSecretKey.encryptBytes(messageBytes, iv); - - // Converting encrypted message into String - final encryptedMessage = String.fromCharCodes(encryptedMessageBytes); - return encryptedMessage; -} -``` - -### Decrypting Messages - -Decrypting a message is the opposite of encrypting one. -To decrypt a message to a human-readable format, use the code snippet below: - -```dart -Future decryptMessage(String encryptedMessage, List deriveKey) async { - // Importing cryptoKey - final aesGcmSecretKey = await AesGcmSecretKey.importRawKey(deriveKey); - - // Converting message into bytes - final messageBytes = Uint8List.fromList(encryptedMessage.codeUnits); - - // Decrypting the message - final decryptedMessageBytes = - await aesGcmSecretKey.decryptBytes(messageBytes, iv); - - // Converting decrypted message into String - final decryptedMessage = String.fromCharCodes(decryptedMessageBytes); - return decryptedMessage; -} -``` - -## Implement as a Stream Chat Feature - -Now that your setup is complete you can use it to implement end-to-end encryption in your app. - -### Store User's Public Key - -The first thing you need to do is store the generated `publicKey` as an `extraData` property, in order -for other users to encrypt messages. - -```dart -// Generating keyPair using the function defined in above steps -final keyPair = generateKeys(); -``` - -```dart -await client.connectUser( - User( - id: 'cool-shadow-7', - name: 'Cool Shadow', - image: 'https://getstream.io/cool-shadow', - - // set publicKey as a extraData property - extraData: { 'publicKey': keyPair.publicKey }, - ), - client.devToken('cool-shadow-7').rawValue, -); -``` - -### Sending Encrypted Messages - -Now you will use the `encryptMessage()` function created in the previous steps to encrypt the message. - -To do that, you need to make some minor changes to the **StreamMessageInput** widget. - -```dart -final receiverJwk = receiver.extraData['publicKey']; - -// Generating derivedKey using user's privateKey and receiver's publicKey -final derivedKey = await deriveKey(keyPair.privateKey, receiverJwk); -``` - -```dart -StreamMessageInput( - - ... - - preMessageSending: (message) async { - // Encrypting the message text using derivedKey - final encryptedMessage = await encryptMessage(message.text, derivedKey); - - // Creating a new message with the encrypted message text - final newMessage = message.copyWith(text: encryptedMessage); - - return newMessage; - }, -), -``` - -`preMessageSending` is a parameter that allows your app to process the message before it goes to Stream’s server. -Here, you have used it to encrypt the message before sending it to Stream’s backend. - -### Showing Decrypted Messages - -Now, it’s time to decrypt the message and present it in a human-readable format to the receiver. - -You can customize the **StreamMessageListView** widget to have a custom `messagebuilder`, that can decrypt the message. - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, currentMessages, defaultWidget) { - // Retrieving the message from details - final message = messageDetails.message; - - // Decrypting the message text using the derivedKey - final decryptedMessageFuture = decryptMessage(message.text, derivedKey); - return FutureBuilder( - future: decryptedMessageFuture, - builder: (context, snapshot) { - if (snapshot.hasError) return Text('Error: ${snapshot.error}'); - if (!snapshot.hasData) return Container(); - - // Updating the original message with the decrypted text - final decryptedMessage = message.copyWith(text: snapshot.data); - - // Returning defaultWidget with updated message - return defaultWidget.copyWith( - message: decryptedMessage, - ); - }, - ); - }, -), -``` - -That's it. That's all you need to implement E2EE in a Stream powered chat app. - -For more details, check out our [end-to-end encrypted chat article](https://getstream.io/blog/end-to-end-encrypted-chat-in-flutter/#whats-end-to-end-encryption). diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/07-error_reporting_with_sentry.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/07-error_reporting_with_sentry.mdx deleted file mode 100644 index dbbe312e80..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/07-error_reporting_with_sentry.mdx +++ /dev/null @@ -1,143 +0,0 @@ ---- -id: error_reporting_with_sentry -title: Error Reporting ---- - -Error Reporting With Sentry - -## Introduction - -While one always tries to create apps that are free of bugs, they're sure to crop up from time to time. Since buggy apps lead to unhappy users and customers, it's important to understand how often your users experience bugs and where those bugs occur. That way, you can prioritize the bugs with the highest impact and work to fix them. - -Whenever an error occurs, create a report containing the error that occurred and the associated stack trace. You can then send the report to an error tracking service, such as [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), or [Firebase Crashlytics](https://firebase.google.com/docs/crashlytics). - -The error tracking service aggregates all of the crashes your users experience and groups them together. This allows you to know how often your app fails and where your users run into trouble. - -In this guide, learn how to report Stream Chat errors to the [Sentry](https://sentry.io/welcome/) crash reporting service using the following steps. - -### 1. Get a DSN From Sentry - -Before reporting errors to Sentry, you need a “DSN” to uniquely identify your app with the Sentry service: -To get a DSN, use the following steps: - -- [Create an account with Sentry](https://sentry.io/signup/). -- Log in to the account. -- Create a new Flutter project. -- Copy the code snippet that includes the DSN. - -### 2. Import the Sentry package - -Import the `sentry_flutter` package into your app. The sentry package makes it easier to send error reports to the Sentry error tracking service. - -```yaml -dependencies: - sentry_flutter: -``` - -### 3. Initialize the Sentry SDK - -Initialize the SDK to capture different unhandled errors automatically. - -```dart -import 'package:sentry_flutter/sentry_flutter.dart'; - -Future main() async { - await SentryFlutter.init( - (options) => options.dsn = 'https://example@sentry.io/example', - appRunner: () => runApp(const MyApp()), - ); -} -``` - -Or, if you want to run your app in your own error zone, use `runZonedGuarded`: - -```dart -void main() async { - /// Captures errors reported by the Flutter framework. - FlutterError.onError = (FlutterErrorDetails details) { - if (kDebugMode) { - // In development mode, simply print to console. - FlutterError.dumpErrorToConsole(details); - } else { - // In production mode, report to the application zone to report to Sentry. - Zone.current.handleUncaughtError(details.exception, details.stack!); - } - }; - - Future _reportError(dynamic error, StackTrace stackTrace) async { - // Print the exception to the console. - if (kDebugMode) { - // Print the full stack trace in debug mode. - print(stackTrace); - return; - } else { - // Send the Exception and Stacktrace to sentry in Production mode. - await Sentry.captureException(error, stackTrace: stackTrace); - } - } - - runZonedGuarded( - () async { - await SentryFlutter.init( - (options) => options.dsn = 'https://example@sentry.io/example', - ); - runApp(const MyApp()); - }, - _reportError, - ); -} -``` - -Alternatively, you can pass the DSN to Flutter using the **dart-define** tag: - -```bash ---dart-define SENTRY_DSN=https://example@sentry.io/example -``` - -### 4. Integration With StreamChat Applications - -Override the default `logHandlerFunction` to send errors to Sentry. - -```dart -void sampleAppLogHandler(LogRecord record) async { - if (kDebugMode) StreamChatClient.defaultLogHandler(record); - - // Report errors to Sentry - if (record.error != null || record.stackTrace != null) { - await Sentry.captureException( - record.error, - stackTrace: record.stackTrace, - ); - } -} - -StreamChatClient buildStreamChatClient( - String apiKey, { - Level logLevel = Level.SEVERE, -}) { - return StreamChatClient( - apiKey, - logLevel: logLevel, - logHandlerFunction: sampleAppLogHandler, // Pass the overridden logHandlerFunction - ); -} -``` - -### 5. Capture Errors Programmatically - -Besides the automatic error reporting that Sentry generates by importing and initializing the SDK, -you can use the API to manually report errors to Sentry: - -```dart -await Sentry.captureException(exception, stackTrace: stackTrace); -``` - -For more information, see the [Sentry API](https://pub.dev/documentation/sentry_flutter/latest/sentry_flutter/sentry_flutter-library.html) docs on Pub. - -### Complete Example - -To view a working example, see the [Stream Sample app](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). - -### Learn More - -Extensive documentation about using the Sentry SDK can be found on [Sentry's site](https://docs.sentry.io/platforms/flutter/). diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/08-adding_chat_to_video_livestreams.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/08-adding_chat_to_video_livestreams.mdx deleted file mode 100644 index 72f501208d..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/08-adding_chat_to_video_livestreams.mdx +++ /dev/null @@ -1,97 +0,0 @@ ---- -id: adding_chat_to_video_livestreams -title: Livestreams Integration ---- - -Adding Chat To Video Livestreams - -### Introduction - -Video livestreams are usually complemented with a chat section to make the livestream more interactive -and encourage retention. There are several ways to show the chat interface on the screen and requires -some design choices. - -This guide details multiple ways of adding chat functionality to your video livestream. - -### Implementing Chat - -There are two common scenarios in live-streaming applications depending how well integrated the two -components (video + chat) are allowed to be on the screen. Two common types are split-screen and a -chat overlay that fades in. - -Let's explore creating both types: - -### Split-screen - -In the split-screen implementation, we have a visual split between the video and the message list. -This allows the content to be unobstructed by chat and have a clear separation of boundaries. - -![](../assets/live_stream_1.jpg) - -```dart -Scaffold( - body: Column( - children: [ - Expanded( - child: // Your video implementation here, - ), - Expanded( - child: Column( - children: [ - Expanded( - child: StreamMessageListView(), - ), - StreamMessageInput(), - ], - ), - ), - ], - ), -) -``` - -### Overlapping chat with a transparency gradient - -Another way to add chat is to overlay the video content with messages which progressively fade out -as we go to the top of the screen. This gives the content a more rich feel as it takes the whole -screen and allows the chat to be more homogeneously integrated with the content. - -The second type looks like this: - -![](../assets/live_stream_2.jpg) - -We can use a `Stack` for achieving this: - -```dart -Stack( - children: [ - // Add your video implementation here - ShaderMask( - shaderCallback: (rect) { - return const LinearGradient( - begin: Alignment.bottomCenter, - end: Alignment.topCenter, - colors: [Colors.black, Colors.transparent], - stops: [0.4, 0.8]).createShader( - Rect.fromLTRB(0, 0, rect.width, rect.height), - ); - }, - blendMode: BlendMode.dstIn, - child: Column( - children: const [ - Expanded( - child: StreamMessageListViewTheme( - data: StreamMessageListViewThemeData( - backgroundColor: Colors.transparent, - ), - child: StreamMessageListView(), - ), - ), - StreamMessageInput(), - ], - ), - ), - ], -), -``` - diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/08-migrations/_category_.json b/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/08-migrations/_category_.json deleted file mode 100644 index e30f7ae440..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/08-migrations/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Migrations" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/08-migrations/migration_guide_4_0.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/08-migrations/migration_guide_4_0.mdx deleted file mode 100644 index e7b6864fa3..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/08-migrations/migration_guide_4_0.mdx +++ /dev/null @@ -1,753 +0,0 @@ ---- -id: migration_guide_4_0 -title: v4.0 -slug: /guides/migration_guide_4_0/ ---- - -**Version 4.0.0** of the Stream Chat Flutter SDK carries significant architectural changes to improve the developer experience by giving you more control and flexibility in how you use our core components and UI widgets. - -This v4.0 Migration Guide is intended to enumerate and better explain the changes in the SDK. - -If you find any bugs or have any questions, please file an [issue on our GitHub repository](https://github.com/GetStream/stream-chat-flutter/issues). We want to support you as much as we can with this migration. - -Code examples: - -- See our [Stream Chat Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) for an up-to-date guide using the latest Stream Chat version. -- See the [Stream Flutter Samples repository](https://github.com/GetStream/flutter-samples) with our full fledged messaging [sample application](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). - -All of our documentation has also been updated to support v4, so all of the guides and examples will have updated code. - -### Dependencies - -To migrate to v4.0.0, update your `pubspec.yaml` with the correct Stream chat package you're using: - -```yaml -dependencies: - stream_chat_flutter: ^4.0.0 # full UI, core and client packages - stream_chat_flutter_core: ^4.0.0 # core and client packages - stream_chat: ^4.0.0 # client package -``` - ---- - -## Name Changes - -The majority of the Stream Chat widgets and classes have now been renamed to have a “Stream” prefix associated with them. This increases Stream widgets' discoverability and avoids name conflicts when importing. - -For example, `MessageListView` is now called `StreamMessageListView`, and `UserAvatar` is renamed to `StreamUserAvatar`. - -**The old class names are deprecated and will be removed in the next major release (v5.0.0).** - -See the sections below on “deprecated classes” for a complete list of changes. Some of these classes/widgets have undergone functional changes as well, that will be explore in the following sections. - -## Removed Functionality/Widgets - -This section highlights functionality removed. - -### Removed Methods And Classes - -In version 4 we removed the following deprecated methods and classes: - -* `Channel.banUser` - -* `Channel.unbanUser` - -* `ClientState.user` - -* `ClientState.userStream` - -* `MessageWidget.allRead` - -* `MessageWidget.readList` - -* `StreamChat.user` - -* `StreamChat.userStream` - -* `StreamChatCore.user` - -* `StreamChatCore.userStream` - -These were marked as deprecated in v3. - -### Video Compression - -The automatic video compression when uploading a video has been removed. You can integrate this yourself by manipulating attachments using a [custom attachment uploader](https://getstream.io/chat/docs/flutter-dart/file_uploads/?language=dart). - -### Slidable Channel List Item - -The default slidable channel preview behavior has been removed. We have created a [guide](../../02-customization/01-custom-widgets/07-slidable_channel_list_preview.mdx) showing you how you can easily add this functionality yourself. - -![Slidable demo](../../assets/slidable_demo.jpg) - -### Pin Permission - -`pinPermissions` is no longer needed in the **MessageListView** widget. The permissions are automatically fetched for each Stream project. To enable users to pin the message, make sure the pin permissions are granted for different types of users on your [Stream application dashboard](https://dashboard.getstream.io/). - ---- - -## Deprecated Classes - -This section covers all the deprecated classes and widgets in the Stream chat packages. Some of these have also undergone functional changes, for example, **MessageInput** and **ChannelsBloc**. These are discussed in more detail below. - -The majority of the Stream widgets and classes have now been renamed to have a **"Stream"** prefix associated with them. - -Changes: - -- `AttachmentTitle` in favor of `StreamAttachmentTitle` -- `AttachmentUploadStateBuilder` in favor of `StreamAttachmentsUploadStateBuilder` -- `AttachmentWidget` in favor of `StreamAttachmentWidget` -- `AvatarThemeData` in favor of `StreamAvatarThemeData` -- `ChannelAvatar` in favor of `StreamChannelAvatar` -- `ChannelBottomSheet` in favor of `StreamChannelInfoBottomSheet` -- `ChannelHeader` in favor of `StreamChannelHeader` -- `ChannelHeaderTheme` in favor of `StreamChannelHeaderTheme` -- `ChannelHeaderThemeData` in favor of `StreamChannelHeaderThemeData` -- `ChannelInfo` in favor of `StreamChannelInfo` -- `ChannelListHeader` in favor of `StreamChannelListHeader` -- `ChannelListHeaderTheme` in favor of `StreamChannelListHeaderTheme` -- `ChannelListHeaderThemeData` in favor of `StreamChannelListHeaderThemeData` -- `ChannelListView` in favor of `StreamChannelListView` -- `ChannelListViewTheme` in favor of `StreamChannelListViewTheme` -- `ChannelListViewThemeData` in favor of `StreamChannelListViewThemeData` -- `ChannelListHeader` in favor of `StreamChannelListHeader` -- `ChannelListView` in favor of `StreamChannelListView` -- `ChannelName` in favor of `StreamChannelName` -- `ChannelPreview` in favor of `StreamChannelListTile` -- `ChannelPreviewTheme` in favor of `StreamChannelPreviewTheme` -- `ChannelPreviewThemeData` in favor of `StreamChannelPreviewThemeData` -- `ChannelName` in favor of `StreamChannelName` -- `ColorTheme` in favor of `StreamColorTheme` -- `CommandsOverlay` in favor of `StreamCommandsOverlay` -- `ConnectionStatusBuilder` in favor of `StreamConnectionStatusBuilder` -- `DateDivider` in favor of `StreamDateDivider` -- `DeletedMessage` in favor of `StreamDeletedMessage` -- `EmojiOverlay` in favor of `StreamEmojiOverlay` -- `FileAttachment` in favor of `StreamFileAttachment` -- `FullScreenMedia` in favor of `StreamFullScreenMedia` -- `GalleryFooter` in favor of `StreamGalleryFooter` -- `GalleryFooterThemeData` in favor of `StreamGalleryFooterThemeData` -- `GalleryHeader` in favor of `StreamGalleryHeader` -- `GalleryHeaderTheme` in favor of `StreamGalleryHeaderTheme` -- `GalleryHeaderThemeData` in favor of `StreamGalleryHeaderThemeData` -- `GiphyAttachment` in favor of `StreamGiphyAttachment` -- `GradientAvatar` in favor of `StreamGradientAvatar` -- `GroupAvatar` in favor of `StreamGroupAvatar` -- `ImageAttachment` in favor of `StreamImageAttachment` -- `ImageGroup` in favor of `StreamImageGroup` -- `InfoTile` in favor of `StreamInfoTile` -- `MediaListView` in favor of `StreamMediaListView` -- `MessageAction` in favor of `StreamMessageAction` -- `MessageActionsModal` in favor `StreamMessageActionsModal` -- `MessageInput` in favor of `StreamMessageInput` -- `MessageInputTheme` in favor of `StreamMessageInputTheme` -- `MessageInputThemeData` in favor of `StreamMessageInputThemeData` -- `MessageInputState` in favor of `StreamMessageInput` -- `MessageListView` in favor of `StreamMessageListView` -- `MessageListViewTheme` in favor of `StreamMessageListViewTheme` -- `MessageListViewThemeData` in favor of `StreamMessageListViewThemeData` -- `MessageSearchListView` in favor of `StreamMessageSearchListView` -- `MessageSearchListViewTheme` in favor of `StreamMessageSearchListViewTheme` -- `MessageSearchListViewThemeData` in favor of `StreamMessageSearchListViewThemeData` -- `MessageReactionsModal` in favor of `StreamMessageReactionsModal` -- `MessageSearchItem` in favor of `StreamMessageSearchItem` -- `MessageSearchListView` in favor of `StreamMessageSearchListView` -- `MessageText` in favor of `StreamMessageText` -- `MessageWidget` in favor of `StreamMessageWidget` -- `MessageThemeData` in favor of `StreamMessageThemeData` -- `MultiOverlay` in favor of `StreamMultiOverlay` -- `OptionListTile` in favor of `StreamOptionListTile` -- `QuotedMessageWidget` in favor of `StreamQuotedMessageWidget` -- `ReactionBubble` in favor of `StreamReactionBubble` -- `ReactionIcon` in favor of `StreamReactionIcon` -- `ReactionPicker` in favor of `StreamReactionPicker` -- `SendingIndicator` in favor of `StreamSendingIndicator` -- `SystemMessage` in favor of `StreamSystemMessage` -- `TextTheme` in favor of `StreamTextTheme` -- `ThreadHeader` in favor of `StreamThreadHeader` -- `TypingIndicator` in favor of `StreamTypingIndicator` -- `UnreadIndicator` in favor of `SteamUnreadIndicator` -- `UploadProgressIndicator` in favor of `StreamUploadProgressIndicator` -- `UrlAttachment` in favor of `StreamUrlAttachment` -- `UserAvatar` in favor of `StreamUserAvatar` -- `UserItem` in favor of `StreamUserItem` -- `UserListView` in favor of `StreamUserListView` -- `UserListViewTheme` in favor of `StreamUserListViewTheme` -- `UserListViewThemeData` in favor of `StreamUserListViewThemeData` -- `UserMentionTile` in favor of `StreamUserMentionTile` -- `UserMentionsOverlay` in favor of `StreamUserMentionsOverlay` -- `VideoAttachment` in favor of `StreamVideoAttachment` -- `VideoService` in favor of `StreamVideoService` -- `VideoThumbnailImage` in favor of `StreamVideoThumbnailImage` -- `VisibleFootnote` in favor of `StreamVisibleFootnote` - -## ChannelListView to StreamChannelListView - -The `ChannelListView` widget has been deprecated, and it is now recommended to use `StreamChannelListView`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `StreamChannelListController`. This controller manages the content for a channel list; it lets you perform tasks such as: - -- Load initial data. -- Use channel events handlers. -- Load more data using `loadMore`. -- Replace the previously loaded channels. -- Return/Create a new channel and start watching it. -- Pause and Resume all subscriptions added to this composite. - -For more information see the [`StreamChannelListView` documentation](../../03-stream_chat_flutter/stream_channel_list_view.mdx). - -### ChannelsBloc to StreamChannelListController - -The `ChannelsBloc` widget should be replaced with `StreamChannelListController`. This controller provides all the functionality needed to query and manipulate channel data previously accessible through `ChannelsBloc`. - -For more information see the [`StreamChannelListController` documentation](../../04-stream_chat_flutter_core/stream_channel_list_controller.mdx). - -### StreamChannelListView Examples - -Let's explore some examples of the functional differences when using the new `StreamChannelListView`. - -The **StreamChannelListController** provides various methods, such as: - -- **`deleteChannel`** -- **`loadMore`** -- **`muteChannel`** -- **`deleteChannel`** - -For a complete list with additional information, see the code documentation. - -#### Basic Use - -The following code demonstrates the old way of creating a **ChannelListPage**, that displays a list of channels: - -```dart -class ChannelListPage extends StatelessWidget { - const ChannelListPage({ - Key? key, - }) : super(key: key); - - @override - // ignore: prefer_expression_function_bodies - Widget build(BuildContext context) { - return Scaffold( - body: ChannelsBloc( - child: ChannelListView( - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - sort: const [SortOption('last_message_at')], - limit: 20, - channelWidget: const ChannelPage(), - ), - ), - ); - } -} -``` - -In **v4** this can now be achieved with the following: - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -As you can see, the **ChannelsBloc** has been replaced with a **StreamChannelListController**, where the **filter**, **limit**, and **sort** arguments can be set. The above code also demonstrates how to refresh the channel list by calling `_controller.refresh()`. - -## MessageSearchListView to StreamMessageSearchListView - -The `MessageSearchListView` widget has been deprecated, and it is now recommended to use `StreamMessageSearchListView`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `StreamMessageSearchListController`. This controller manages the content when searching for a message; it lets you perform tasks such as: - -- Load initial data. -- Set filters and search terms. -- Load more data using `loadMore`. -- Refresh data. - -For more information see the [`StreamMessageSearchListView` documentation](../../03-stream_chat_flutter/stream_message_search_list_view.mdx). - -### MessageSearchBloc to StreamMessageSearchListController - -The `MessageSearchBloc` widget should be replaced with a `StreamMessageSearchListController`. This controller provides all the functionality needed to query and manipulate message search data previously accessible through `MessageSearchBloc`. - -For more information see the [`StreamMessageSearchListController` documentation](../../04-stream_chat_flutter_core/stream_message_search_list_controller.mdx). - -### StreamMessageSearchListView Example - -The following code demonstrates the old way of searching for messages: - -```dart -class SearchExample extends StatelessWidget { - const SearchExample({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return MessageSearchBloc( - child: MessageSearchListView( - showErrorTile: true, - messageQuery: 'message query', - filters: Filter.in_('members', const ['user-id']), - sortOptions: const [ - SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - pullToRefresh: false, - limit: 30, - emptyBuilder: (context) => const Text('Nothing to show'), - itemBuilder: (context, messageResponse) { - /// Return widget - } - onItemTap: (messageResponse) { - /// Handle on tap - } - ), - ); - } -} -``` - -In **v4**, this can now be achieved with the following: - -```dart -class SearchExample extends StatefulWidget { - const SearchExample({ - Key? key, - }) : super(key: key); - - @override - State createState() => _SearchExampleState(); -} - -class _SearchExampleState extends State { - late final StreamMessageSearchListController _messageSearchListController = - StreamMessageSearchListController( - client: StreamChat.of(context).client, - filter: Filter.in_('members', [StreamChat.of(context).currentUser!.id]), - limit: 5, - searchQuery: '', - sort: [ - const SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - ); - - search() { - _messageSearchListController.searchQuery = 'search-value'; - _messageSearchListController.doInitialLoad(); - } - - @override - dispose() { - _messageSearchListController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return StreamMessageSearchListView( - controller: _messageSearchListController, - emptyBuilder: (context) => const Text('Nothing to show'), - itemBuilder: ( - context, - messageResponses, - index, - defaultWidget, - ) { - return defaultWidget.copyWith(); // modify default widget - }); - } -} -``` - -## UserListView to StreamUserListView - -The `UserListView` widget has been deprecated, and it is now recommended to use `StreamUserListView`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `StreamUserListController`. This controller manages the content when retrieving Stream users; it let's you perform tasks, such as: - -- Load data. -- Set filters. -- Refresh data. - -For more information see the [`StreamUserListView` documentation](../../03-stream_chat_flutter/stream_user_list_view.mdx). - -### UsersBloc to StreamUserListController - -The `UsersBloc` widget should be replaced with a `StreamUserListController`. This controller provides all the functionality needed to query and manipulate user data previously accessible through `UsersBloc`. - -For more information see the [`StreamUserListController` documentation](../../04-stream_chat_flutter_core/stream_user_list_controller.mdx). - -### StreamUserListView Example - -The following code demonstrates the old way of displaying all users: - -```dart -class UsersExample extends StatelessWidget { - const UsersExample({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return UsersBloc( - child: UserListView( - groupAlphabetically: true, - onUserTap: (user, _) { - /// Handle on tap - }, - limit: 25, - filter: Filter.and([ - Filter.autoComplete('name', 'some-name'), - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]), - sort: const [ - SortOption( - 'name', - direction: 1, - ), - ], - ), - ); - } -} -``` - -In **v4**, this can now be achieved with the following: - -```dart -class UsersExample extends StatefulWidget { - const UsersExample({ - Key? key, - }) : super(key: key); - - @override - State createState() => _UsersExampleState(); -} - -class _UsersExampleState extends State { - late final userListController = StreamUserListController( - client: StreamChat.of(context).client, - limit: 25, - filter: Filter.and([ - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - void _load() { - userListController.filter = Filter.and([ - Filter.autoComplete('name', 'some-name'), - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]); - userListController.doInitialLoad(); - } - - @override - dispose() { - userListController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return StreamUserListView( - controller: userListController, - onUserTap: (user) { - /// Handle on tap - }, - emptyBuilder: (context) => const Text('Nothing to show'), - itemBuilder: ( - context, - users, - index, - defaultWidget, - ) { - return defaultWidget.copyWith(); // modify default widget - }, - ); - } -} -``` - -## MessageInput to StreamMessageInput - -The `MessageInput` widget has been deprecated, and it is now recommended to use `StreamMessageInput`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `MessageInputController`. This controller maintains the state of the message input and exposes various methods to allow you to customize and manipulate the underlying **Message** value. - -Creating a separate controller allows easier control over the message input content by moving logic out of the deprecated `MessageInput` and into the controller. This controller can then be created, managed, and exposed in whatever way you like. - -The widget is also separated into smaller components: `StreamCountDownButton`, `StreamAttachmentPicker`, etc. - -> ❗The `MessageInputController` is exposed by the **`stream_chat_flutter_core`** package. This allows you to use the controller even if you're not using the UI components. - -As a result of this extra control, it is no longer needed for the new `StreamMessageInput` widget to expose these `MessageInput` arguments: - -- `parentMessage`: parent message in case of a thread -- `editMessage`: message to edit -- `initialMessage`: message to start with -- `quotedMessage`: message to quote/reply -- `onQuotedMessageCleared`: callback for clearing quoted message -- `textEditingController`: the text controller of the text field - -The following arguments are newly introduced to the `StreamMessageInput`, and are not available on the old `MessageInput`: - -- `messageInputController`: the controller for the message input -- `attachmentsPickerBuilder`: builder for bottom sheet when attachment picker is opened -- `sendButtonBuilder`: builder for creating send button -- `validator`: a callback function that validates the message -- `restorationId`: restoration ID to save and restore the state of the MessageInput -- `enableSafeArea`: wraps the **StreamMessageInput** widget with a **SafeArea** widget -- `elevation`: elevation of the **StreamMessageInput** widget -- `shadow`: **Shadow** for the **StreamMessageInput** widget - -For more information see the [`StreamMessageInput` documentation](../../04-stream_chat_flutter_core/stream_message_input_controller.mdx). - -### StreamMessageInput Examples - -Let's explore some examples of the functional differences when using the new `StreamMessageInput`. - -#### Basic Use - -Unless you want to programmatically manipulate the value of the message input, then there is no difference in how you would use the message input widget. - -The following code demonstrates the old way of creating a **ChannelPage** widget that displays a chat screen: - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: const ChannelHeader(), - body: Column( - children: const [ - Expanded( - child: MessageListView(), - ), - MessageInput(), - ], - ), - ); - } -} -``` - -In **v4** this is the same, the only difference being that all the Stream widgets are now prefixed with **Stream**. For example, **MessageListView** becomes **StreamMessageListView**, and so forth. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) => Scaffold( - appBar: const StreamChannelHeader(), - body: Column( - children: const [ - Expanded( - child: StreamMessageListView(), - ), - StreamMessageInput(), - ], - ), - ); -} -``` - -However, you can optionally pass in a **MessageInputController** in the **StreamMessageInput**, which gives extra control over the message input value. - -#### Thread Page - -The following code demonstrates the old way of creating a thread page: - -```dart -class ThreadPage extends StatelessWidget { - const ThreadPage({ - Key? key, - this.parent, - }) : super(key: key); - - final Message? parent; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: ThreadHeader( - parent: parent!, - ), - body: Column( - children: [ - Expanded( - child: MessageListView( - parentMessage: parent, - ), - ), - MessageInput( - parentMessage: parent, - ), - ], - ), - ); - } -} -``` - -In **v4** the only difference is the **Stream** prefix and the way that the parent message is passed to the message input: - -```dart -class ThreadPage extends StatelessWidget { - const ThreadPage({ - Key? key, - this.parent, - }) : super(key: key); - - final Message? parent; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: StreamThreadHeader( - parent: parent!, - ), - body: Column( - children: [ - Expanded( - child: StreamMessageListView( - parentMessage: parent, - ), - ), - StreamMessageInput( - messageInputController: MessageInputController( - message: Message(parentId: parent!.id), - ), - ), - ], - ), - ); - } -} -``` - -To send a thread message, you need to specify the message's parent ID for which you're creating a thread. - -#### Reply/Quote Message - -The following code demonstrates the old way of replying to a message: - -```dart -... - -void _reply(Message message) { - setState(() => _quotedMessage = message); -} - -... - -MessageInput - quotedMessage: _quotedMessage, - onQuotedMessageCleared: () { - setState(() => _quotedMessage = null); - }, -), -``` - -To reply to a message in **v4**: - -```dart -... - -void _reply(Message message) { - _messageInputController.quotedMessage = message; -} - -... - -StreamMessageInput( - messageInputController: _messageInputController, -), -``` - -The controller makes it much simpler to dynamically modify the message input. - -## Stream Chat Flutter Core - -Various changes have been made to the Core package, most notably, the introduction of all of the controllers mentioned above. - -These controllers replace the business logic implementations (Bloc). Please note that this is not related to the well-known Flutter Bloc package, but instead refers to the naming we used for our business logic components. - -In this version we're introducing controllers in place of their bloc counterparts: -**StreamChannelListController** in favor of **ChannelsBloc** -**StreamMessageSearchListController** in favor of **MessageSearchBloc** -**StreamUserListController** in favor of **UsersBloc** - -The Bloc components are deprecated in v4.0.0 but can still be used. They will be removed in the next major release (v5.0.0). - -Additionally, we also now have the **StreamMessageInputController**, as discussed above. This can be used outside of our UI package as well. - -Finally, the following Core builders are also deprecated as their functionality can be replaced using their controller counterparts: - -- ChannelListCore -- MessageSearchListCore -- UserListCore diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/08-migrations/migration_guide_5_0.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/08-migrations/migration_guide_5_0.mdx deleted file mode 100644 index 106a1909ac..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/08-migrations/migration_guide_5_0.mdx +++ /dev/null @@ -1,174 +0,0 @@ ---- -id: migration_guide_5_0 -title: v5.0 -slug: /guides/migration_guide_5_0/ ---- - -**Version 5.0.0** of the Stream Chat Flutter SDK UI package has been overhauled to support larger screen sizes better and provide native feeling web and desktop platform interactions that feel intuitive and expected. - -These newly introduced changes are platform-dependent and will not affect your current Android and iOS builds. - -This guide enumerates and better explains the SDK changes introduced in v5. - -If you find any bugs or have any questions, please file an [issue on our GitHub repository](https://github.com/GetStream/stream-chat-flutter/issues). We want to support you as much as we can with this migration. - -Code examples: - -- See our [Stream Chat Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) for an up-to-date guide using the latest Stream Chat version. -- See the [Stream Flutter Samples repository](https://github.com/GetStream/flutter-samples) with our full fledged messaging [sample application](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). - -Our documentation has also been updated to support v5, so all guides and examples will have updated code. - -### Dependencies - -To migrate to v5.0.0, update your `pubspec.yaml` with the correct Stream chat package you're using: - -```yaml -dependencies: - stream_chat_flutter: ^5.0.0 # full UI, core and client packages - stream_chat_flutter_core: ^5.0.0 # core and client packages - stream_chat: ^5.0.0 # client package -``` - ---- - -## Desktop and Web Support: What Changed? - -This section highlights our efforts on Desktop (macOS, Windows, and Linux) and Web support. - -### Setup - -See the [setup guide](../../03-stream_chat_flutter/setup.mdx) for platform specific instructions. - -### Supporting Larger Screens - -We've added support for larger screens and have made changes to the UI to support larger screen sizes better. - -- Widgets are constrained to a maximum size, for example, appropriate message sizing for larger screens. -- UI changes to use larger screen real estate. For example, reactions are added to the bottom of a message on desktop and web. - -Below is an example running on macOS, with a split-screen view showing channels on the left and messages on the right. - -![MacOS split](../../assets/mac_os_split.png) - -### Native Platform Interactions - -The user experience of interacting with a desktop application differs from a mobile counterpart. There are several factors to consider for an application to feel native and intuitive on the platform it is running, for example: - -- Input controls: touch, keyboard, and mouse interactions -- Native file system or gallery access (as well as sharing functionality) -- Shortcuts -- Dialog screens - -By default, Stream Chat Flutter will use the correct input controls and visual elements for the target platform. For example, touch and swipe controls will be the default on mobile, while on web and desktop these will be disabled and interactions with the mouse and keyboard will be preferred. - -On desktop and web it's also possible to add attachments by simply dragging them into the message input box. - -### All UI/Behaviour Changes for Desktop and Web - -- Right-click context menus for messages and full-screen attachments. -- Upload and download attachments using the native desktop file system. -- Press the "enter" key to send a message. -- If you are quoting a message and have not yet typed any text, you can press the `"esc"` key to remove the quoted message. -- A dedicated "X" button for removing a quoted message with your mouse. -- Drag and drop attachment files to `StreamMessageInput`. -- New `StreamMessageInput.draggingBorder` property to customize the border color of the message input when dropping a file. -- Message reactions bubbles differ per platform. -- Hovering over a message reaction will show the users that have reacted to the message. -- Desktop attachment sharing UI. -- Selectable message text with mouse input. -- Gallery navigation controls with keyboard shortcuts (left and right arrow keys). -- Appropriate message sizing for large screens. -- Right-click context menu for `StreamMessageListView` items. -- `StreamMessageListView` items not swipe-able on desktop & web. -- Video support for Windows & Linux through `dart_vlc`. -- Video support for macOS through `video_player_macos`. -- Replace bottom sheets with dialog screens where appropriate. - -## What's New? - -We improved the overall user experience of the Stream Chat Flutter SDK and added new features to make it easier to customize the SDK to your needs. - -We've also fixed several bugs and improved the overall stability of the SDK. - -### StreamChatConfiguration - -The `StreamChatConfiguration` class is a new inherited widget that allows you to configure the Stream Chat Flutter SDK. - -It provides a few configuration options. For example, it lets you specify if you want to `enforceUniqueReactions` or not and allows you to set the `reactionIcons` to use in your app. - -You can retrieve the current configuration using `StreamChatConfiguration.of(context)`, as long as there is a `StreamChat` or `StreamChatConfiguration` widget higher up the widget tree. You can provide a custom `StreamChatConfigurationData` directly to `StreamChat` or wrap a section of the widget tree with a `StreamChatConfiguration`. - -For additional information, see [#1125](https://github.com/GetStream/stream-chat-flutter/issues/1125). The `defaultUserImage`, `placeholderUserImage`, `reactionIcons`, and `enforceUniqueReactions` have been refactored out of `StreamChatThemeData` and into the new`StreamChatConfigurationData` class. - -### StreamMemberListView and StreamMemberGridView - -The `StreamMemberListView` and `StreamMemberGridView` widgets are new widgets that allow you to display a list of members in a channel. - -Check out the dedicated [documentation](../../03-stream_chat_flutter/stream_member_list_view.mdx) for more information. - -### Attachment Picker - -As part of the v5 release, we've refactored the `AttachmentPicker` to be more flexible and customizable. This allows you to use the `AttachmentPicker` in various ways and customize the UI to your liking. - -Check out the dedicated [guide](../../02-customization/01-custom-widgets/05-customize_attachment_picker_modal.mdx) for more information. - -### Other Changes - -The following was also introduced: - -- Added support for additional text field parameters in`StreamMessageInput`: `maxLines`, `minLines`, `textInputAction`, `keyboardType`, and `textCapitalization`. -- Added `showStreamAttachmentPickerModalBottomSheet` to show the attachment picker modal bottom sheet. -- Added `onQuotedMessageCleared` to `StreamMessageInput` -- `selected` and `selectedTileColor` to `StreamChannelListTile` -- Added `AttachmentUploadStateBuilder.inProgressBuilder` to `AttachmentUploadStateBuilder` -- Added `AttachmentUploadStateBuilder.successBuilder` to `AttachmentUploadStateBuilder` -- Added `AttachmentUploadStateBuilder.failedBuilder` to `AttachmentUploadStateBuilder` -- Added `StreamAutocomplete` widget for auto-complete triggers in `StreamMessageInput`. -- Added `StreamMessageInput.customAutocompleteTriggers` to allow users to define their custom triggers. - -New translations: - -- `couldNotReadBytesFromFileError` -- `downloadLabel` -- `toggleMuteUnmuteAction` -- `toggleMuteUnmuteGroupQuestion` -- `toggleMuteUnmuteGroupText` -- `toggleMuteUnmuteUserQuestion` -- `toggleMuteUnmuteUserText` - -## Deprecated - -The following components have been deprecated in v5.0.0: - -- Deprecated `showConfirmationDialog` in favor of `showConfirmationBottomSheet` -- Deprecated `showInfoDialog` in favor of `showInfoBottomSheet` -- Deprecated `wrapAttachmentWidget` in favor of the `WrapAttachmentWidget` class - -## Breaking changes - -The following components have been removed in v5.0.0: - -- `StreamImageAttachment.size` has been removed in favor of `StreamImageAttachment.constraints`. -- `StreamFileAttachment.size` has been removed in favor of `StreamFileAttachment.constraints`. -- `StreamGiphyAttachment.size` has been removed in favor of `StreamGiphyAttachment.constraints`. -- `StreamVideoAttachment.size` has been removed in favor of `StreamVideoAttachment.constraints`. -- `StreamVideoThumbnailImage.width` and `StreamVideoThumbnailImage.height` have been removed in favor of `StreamVideoThumbnailImage.constraints`. - -To fix these deprecations in your code, you can use a `BoxConstraints.tight` passing the desired fixed size as a parameter. - -```dart -/// BEFORE -StreamImageAttachment( - size: size, -) - -/// AFTER -StreamImageAttachment( - constraints: BoxConstraints.tight(size), -) -``` - -- Removed `StreamMessageInput.customOverlays` in favor of `StreamMessageInput.customAutocompleteTriggers`. Read the guide on [Adding Custom Autocomplete Triggers](../../02-customization/01-custom-widgets/06-autocomplete_triggers.mdx) to learn how to migrate your code. - -- Removed the default emoji overlay picker. Read the guide on [Adding Custom Autocomplete Triggers](../../02-customization/01-custom-widgets/06-autocomplete_triggers.mdx) to learn how to migrate your code. diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/09-initialize_stream_chat_widget_tree.mdx b/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/09-initialize_stream_chat_widget_tree.mdx deleted file mode 100644 index 0f1bd86f72..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/09-initialize_stream_chat_widget_tree.mdx +++ /dev/null @@ -1,699 +0,0 @@ ---- -id: initialize_stream_chat_widget_tree -title: Initialize Stream Chat in Part of the Widget Tree ---- - -If you’re creating a full-scale chat application, you probably want to have Stream Chat Flutter initialized at the top of your widget tree and the Stream user connected as soon as they open the application. - -However, if you only need chat functionality in a part of your application, then it’ll be better to delay Stream Chat initialization to when it’s needed. -This guide demonstrates three alternative ways for you to initialize Stream Chat Flutter for a part of your widget tree and to only connect a user when needed. - -## What To Keep In Mind? - -Before investigating potential solutions, let’s first take a look at the relevant Stream Chat widgets and classes. - -Most of the Stream Chat Flutter UI widgets rely on having a [StreamChat](../../customization/stream_chat_and_theming/) ancestor in the widget tree. -The **StreamChat** widget is an [InheritedWidget](https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html) that exposes the **StreamChatClient** through **BuildContext**. -This widget also initializes the [StreamChatCore](../04-stream_chat_flutter_core/stream_chat_core.mdx) widget and the **StreamChatTheme**. - -**StreamChatCore** is a **StatefulWidget** used to react to life cycle changes and system updates. -When the app goes into the background, the WebSocket connection is closed. -Conversely, a new connection is initiated when the app is back in the foreground. - -What is important to take note of is that **a connection is only established if a user is connected**. - -This means that if you have not yet called `client.connectUser(user, token)`, no connection will be made, and only background listeners will be registered to determine the app's foreground state. - -## Option 1: Builder and Connect/Disconnect User - -This option requires you to wrap your whole application with the **StreamChat** widget and to call `connectUser` and `disconnectUser` as needed. - -This option is the easiest, however, it requires **StreamChat** to be at the top of each route and as a result, will have a slight overhead as it’ll create the above-mentioned Stream widgets that may not yet be needed. - -### Exposing the StreamChat Widget - -First, you must expose the client and base Stream Chat widgets to the whole application. - -```dart -void main() { - final client = StreamChatClient( - 'q29npdvqjr99', - logLevel: Level.OFF, - ); - - 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) { - return StreamChat(client: client, child: child); - }, - home: const HomeScreen(), - ); - } -} -``` - -In the above code, you: - -1. Create a **StreamChatClient** instance -2. Pass the instance to the **StreamChat** widget -3. Expose **StreamChat** to the whole application within the **MaterialApp** `builder` - -A few important things to note: - -- The `builder` wraps the **StreamChat** widget for every route of our application. No matter where you are in the widget tree, you’ll be able to call `StreamChat.of(context)`. -- The state will only be created once for our application, as **StreamChat** is a **StatefulWidget** and the position of **StreamChat** in the widget tree remains the same throughout the application lifecycle. -- No connection will be made until you call `connectUser`. - -### Connecting and Disconnecting Users - -In **MaterialApp** above, the home page is set to **HomeScreen**. This screen could look something like the following: - -```dart -class HomeScreen extends StatelessWidget { - const HomeScreen({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(), - body: const Center( - child: Text('Home Screen'), - ), - floatingActionButton: FloatingActionButton( - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute(builder: (context) => const ChatSetup())); - }, - child: const Icon( - Icons.message, - ), - ), - ); - } -} -``` - -This screen shows a floating action button that on click navigates the user to the **ChatSetup**. We want to connect and disconnect a Stream user only when they go to the chat setup screen. - -```dart -class ChatSetup extends StatefulWidget { - const ChatSetup({ - super.key, - }); - - @override - State createState() => _ChatSetupState(); -} - -class _ChatSetupState extends State { - late final Future connectionFuture; - late final client = StreamChat.of(context).client; - - @override - void initState() { - super.initState(); - connectionFuture = client.connectUser( - User(id: 'USER_ID'), - 'TOKEN', - ); - } - - @override - void dispose() { - client.disconnectUser(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(), - body: FutureBuilder( - future: connectionFuture, - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return const Center( - child: CircularProgressIndicator(), - ); - default: - if (snapshot.hasError) { - return Text('Error: ${snapshot.error}'); - } else { - return const ChannelListPage(); - } - } - }, - ), - ); - } -} -``` - -Within `initState` you call `connectUser`; once the future for `connectUser` has completed a connection to the Stream API is established, you can then display the relevant Stream Chat UI widgets. - -Once the **ChatScreen** widget is disposed of, then `disconnectUser` will be called within the `dispose` method. - -### Caution - -In this example, `disconnectUser` will **only** be called when the **ChatSetup** widget is disposed. - -You need to ensure that this widget (route) is completely disposed of, or you need to call `disconnectUser` and `connectUser` manually when navigating to relevant parts of your application. - -For example, let’s say you have a button within one of the chat screens to navigate to a completely different part of your app, then you want to make sure the **ChatScreen** route is disposed of by forcing it to be removed: - -```dart -Navigator.of(context).pushAndRemoveUntil( - MaterialPageRoute( - builder: ((context) => const HomeScreen()), - ), - (Route route) => false, -); -``` - -Or let’s say you wanted to pop back to the first route: - -```dart -Navigator.of(context).popUntil((route) => route.isFirst); -``` - -Both of these will ensure the route is disposed of and the user is disconnected as a result. - -## Option 2: A Nested Navigator - -Another approach would be to introduce a new [Navigator](https://api.flutter.dev/flutter/widgets/Navigator-class.html). -This has the benefit that everything related to Stream chat is contained to a specific part of the widget tree. - -### Defining Routes and Nested Routes - -In this example, our application has the following routes. - -```dart -const routeHome = '/'; -const routePrefixChat = '/chat/'; -const routeChatHome = '$routePrefixChat$routeChatChannels'; -const routeChatChannels = 'chat_channels'; -const routeChatChannel = 'chat_channel'; -``` - -For the `/chat/` nested routes (**routePrefixChat**), this approach initializes Stream Chat in our application and introduces a nested navigator. - -Let’s explore the code: - -```dart -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatefulWidget { - const MyApp({ - Key? key, - }) : super(key: key); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - final GlobalKey navigatorKey = GlobalKey(); - - @override - Widget build(BuildContext context) { - return Provider.value( - value: navigatorKey, - child: MaterialApp( - navigatorKey: navigatorKey, - initialRoute: routeHome, - onGenerateRoute: (settings) { - late Widget page; - if (settings.name == routeHome) { - page = const HomeScreen(); - } else if (settings.name!.startsWith(routePrefixChat)) { - final subRoute = settings.name!.substring(routePrefixChat.length); - page = ChatSetup( - setupChatRoute: subRoute, - ); - } else { - throw Exception('Unknown route: ${settings.name}'); - } - - return MaterialPageRoute( - builder: (context) { - return page; - }, - settings: settings, - ); - }, - ), - ); - } -} -``` - -In the above code you’re: - -1. Creating a navigator key, passing it to `MaterialApp`, and exposing it to the whole application using Provider (you can expose it however you want). -2. Creating `onGenerateRoute` that specifies what page to show depending on the route. Most importantly, if the route contains the **routePrefixChat,** it navigates to the **ChatSetup** page and passes in the remainder of the route. - -For example, `Navigator.pushNamed(context, routeChatHome)` will navigate to the **ChatSetup** page and pass in the nested route **routeChatChannels.** - -### Stream Chat Initialization, User Connection, and Nested Navigation - -Within the **ChatSetup** widget, we’ll initialize Stream chat, connect a user, and create a new Navigator that handles the sub-navigation for the chat-specific pages. - -```dart -class ChatSetup extends StatefulWidget { - const ChatSetup({Key? key, required this.setupChatRoute}) : super(key: key); - - final String setupChatRoute; - - @override - State createState() => _ChatSetupState(); -} - -class _ChatSetupState extends State { - late final Future connectionFuture; - late final client = StreamChatClient( - 'KEY', - logLevel: Level.OFF, - ); - - @override - void initState() { - super.initState(); - connectionFuture = client.connectUser( - User(id: 'USER_ID'), - 'TOKEN', - ); - } - - @override - void dispose() { - client.disconnectUser(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Material( - child: StreamChat( - client: client, - child: FutureBuilder( - future: connectionFuture, - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return const Center( - child: CircularProgressIndicator(), - ); - default: - if (snapshot.hasError) { - return Text('Error: ${snapshot.error}'); - } else { - return Navigator( - initialRoute: widget.setupChatRoute, - onGenerateRoute: _onGenerateRoute, - ); - } - } - }, - ), - ), - ); - } - - Route _onGenerateRoute(RouteSettings settings) { - late Widget page; - switch (settings.name) { - case routeChatChannels: - page = ChannelListPage( - client: client, - ); - break; - case routeChatChannel: - final channel = settings.arguments as Channel; - page = StreamChannel( - channel: channel, - child: const ChannelPage(), - ); - break; - default: - throw Exception('Unknown route: ${settings.name}'); - } - return MaterialPageRoute( - builder: (context) { - return page; - }, - settings: settings, - ); - } -} -``` - -This **ChatSetup** widget is similar to what it was in the first option, the only difference is that we’re also introducing a nested navigator and handling those nested routes. - -The steps for the above code are: - -1. Create a **StreamChatClient** instance -2. Call `connectUser` within `initState` and await the result using a **FutureBuilder** -3. Introduce a **StreamChat** widget into the widget tree -4. Introduce a new **Navigator** for the chat-specific routes -5. Call `disconnectUser` within `dispose` - -### Displaying Stream Chat UI Widgets and Global Navigation - -Then finally, the **ChannelListPage** could look something like the following: - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - void _popChatPages() { - final nav = context.read>(); - nav.currentState!.pop(); - } - - @override - Widget build(BuildContext context) { - return WillPopScope( - onWillPop: () async { - _popChatPages(); - return true; - }, - child: Scaffold( - appBar: AppBar( - leading: BackButton( - onPressed: () { - _popChatPages(); - }, - ), - ), - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) { - Navigator.pushNamed(context, routeChatChannel, - arguments: channel); - }, - ), - ), - ), - ); - } -} -``` - -There are two important things to note in the above code: - -- We’re accessing the global **NavigatorState** using Provider and calling `pop()` on the back press. This will ensure that this entire route is disposed of and that the Stream connection is closed. -- Within `onChannelTap` we’re calling `pushNamed` and passing in the route to display a single channel page. This uses the navigator introduced in **ChatSetup**, which is the closest navigator within the widget tree. - -A few things to take note of: - -- You’ll always need to access the global navigator if you want to dispose of this route. you need to ensure that this route is popped or replaced, otherwise, the Stream connection will remain active for as long as the chat route is on the stack (or manually disconnected). - -## Option 3: Navigator 2.0 - Using GoRouter - -This final example will be a combination of the first two options. The following code is an example of how to initialize Stream Chat in a part of the widget tree using the [GoRouter package](https://pub.dev/packages/go_router). This solution will change depending on how you do routing in your Flutter application and which package (if any) you use. - -### Application Routes and Conditional Stream Initialization - -For this example we have the following routes and nested routes: - -```dart -|_ '/' -> home page - |_ 'settings/' - settings page - |_ 'chat/' - chat home, shows the channels list page - |_ 'channel/' - specific channel page -``` - -In the **MyApp** widget, we’ll initialize **GoRouter** and the **StreamChatClient**. -However, we will only expose the **StreamChat** widget for certain routes. -Additionally, we’ll create a **ChatSetup** widget that connects and disconnects the user. -This widget will also **only** be injected for the `/chat` routes. - -```dart -class MyApp extends StatefulWidget { - const MyApp({ - Key? key, - }) : super(key: key); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - final _client = StreamChatClient( - 'q29npdvqjr99', - logLevel: Level.OFF, - ); - bool wasPreviousRouteChat = false; - - late final _router = GoRouter( - initialLocation: '/', - routes: [ - ShellRoute( - builder: (context, state, child) { - if (state.uri.host.startsWith('/chat')) { - wasPreviousRouteChat = true; - return StreamChat( - client: _client, - child: ChatSetup(client: _client, child: child), - ); - } else { - if (wasPreviousRouteChat) { - wasPreviousRouteChat = false; - return StreamChat( - client: _client, - child: child, - ); - } else { - return child; - } - } - }, - routes: [ - GoRoute( - path: '/', - builder: (context, state) => const HomeScreen(), - routes: [ - GoRoute( - path: 'settings', - builder: (context, state) => const SettingsPage(), - ), - GoRoute( - path: 'chat', - builder: (context, state) => const ChannelListPage(), - routes: [ - GoRoute( - path: 'channel', - builder: (context, state) { - final channel = state.extra as Channel; - return StreamChannel( - channel: channel, - child: const ChannelPage(), - ); - }, - ), - ], - ), - ], - ), - ], - ), - ], - ); - - @override - Widget build(BuildContext context) { - return MaterialApp.router( - routeInformationParser: _router.routeInformationParser, - routeInformationProvider: _router.routeInformationProvider, - routerDelegate: _router.routerDelegate, - ); - } -} -``` - -If you’re unfamiliar with GoRouter it will help to first read the documentation and then come back to this guide. - -There are a few important things to note in the above code: - -- Define our routes and nested routes -- Specify the initial route with `initialLocation` -- Use the `navigatorBuilder` to wrap certain routes with **StreamChat** and **ChatSetup**. - - The `wasPreviousRouteChat` \***\*boolean is used to determine if the previous route was a chat route. This is important because when you press the back button from the `/chat` route and navigate to the `/` route, the **StreamChat** widget still needs to be accessible while the navigation transition occurs. However, if you then navigate to the `/setting` route, you no longer need the **StreamChat\*\* widget and can safely remove it. - -### Navigating With GoRouter - -Within the **HomeScreen** you can create a button that on press navigates to the `/chat` route: - -```dart -GoRouter.of(context).go('/chat'); -``` - -### Connecting and Disconnecting Users - -Same as before, we’ll use the **ChatSetup** widget to connect and disconnect a user. -This time the widget also takes in a **child** widget to display once the connection is finished. -The child widget is dependent on the route we’re navigating to. - -```dart -class ChatSetup extends StatefulWidget { - const ChatSetup({ - Key? key, - required this.client, - required this.child, - }) : super(key: key); - - final StreamChatClient client; - final Widget child; - - @override - State createState() => _ChatSetupState(); -} - -class _ChatSetupState extends State { - late final Future connectionFuture; - - @override - void initState() { - super.initState(); - connectionFuture = widget.client.connectUser( - User(id: 'USER_ID'), - 'TOKEN', - ); - } - - @override - void dispose() { - widget.client.disconnectUser(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Material( - child: FutureBuilder( - future: connectionFuture, - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return const Center( - child: CircularProgressIndicator(), - ); - default: - if (snapshot.hasError) { - return Text('Error: ${snapshot.error}'); - } else { - return widget.child; - } - } - }, - ), - ); - } -} -``` - -This will connect the Stream chat user within `initState` and disconnect the user on `dispose`. This is similar to the previous examples we explored. - -### Displaying the Stream UI Widgets - -The **ChannelListPage** can look something like the following: - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - super.key, - }); - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final client = StreamChat.of(context).client; - late final _controller = StreamChannelListController( - client: client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(), - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) { - GoRouter.of(context).go('/chat/channel', extra: channel); - }, - ), - ), - ); - } -} -``` - -This is the same as before, the only difference is that the navigation is slightly different; now we’re navigating to the `/chat/channel` route for individual channel pages. - -## Conclusion - -This guide demonstrated three different ways to initialize Stream Chat in a part of the Flutter widget tree. - -There are two key takeaways - -1. Accessing **StreamChat** depends on your location in the widget tree -2. How you ultimately decide to expose **StreamChat** and connect users will be up to your application architecture and how you manage routing. - -The above are only examples that can be refined and tweaked to suit your needs. diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/_category_.json b/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/_category_.json deleted file mode 100644 index 14a4f173f0..0000000000 --- a/docusaurus/flutter_versioned_docs/version-5.x.x/05-guides/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Guides" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/authentication_demo_app.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/authentication_demo_app.jpg deleted file mode 100644 index eed57c3374..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/authentication_demo_app.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_header.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_header.png deleted file mode 100644 index 98f41c614b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_header.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_header_custom_title.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_header_custom_title.png deleted file mode 100644 index 65a9ee75a6..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_header_custom_title.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_list_header.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_list_header.png deleted file mode 100644 index 6f112db9be..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_list_header.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_list_header_custom_subtitle.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_list_header_custom_subtitle.png deleted file mode 100644 index 3c7798570a..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_list_header_custom_subtitle.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_list_view.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_list_view.png deleted file mode 100644 index a4390c2eac..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_preview.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_preview.png deleted file mode 100644 index 39f5629bb8..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/channel_preview.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/chat_basics.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/chat_basics.png deleted file mode 100644 index 82e27cfa49..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/chat_basics.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png deleted file mode 100644 index 9e92437dbf..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/dashboard_firebase_enable.jpeg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/dashboard_firebase_enable.jpeg deleted file mode 100644 index e4696ec882..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/dashboard_firebase_enable.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/dashboard_firebase_key.jpeg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/dashboard_firebase_key.jpeg deleted file mode 100644 index 87243e91f6..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/dashboard_firebase_key.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/dashboard_save_changes.jpeg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/dashboard_save_changes.jpeg deleted file mode 100644 index 1c58a93e63..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/dashboard_save_changes.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/end_to_end_encryption.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/end_to_end_encryption.png deleted file mode 100644 index b41e11ced6..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/end_to_end_encryption.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/firebase_authentication_dashboard.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/firebase_authentication_dashboard.jpg deleted file mode 100644 index c304055768..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/firebase_authentication_dashboard.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/firebase_cloud_secrets_management.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/firebase_cloud_secrets_management.jpg deleted file mode 100644 index 4f131df4cc..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/firebase_cloud_secrets_management.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png deleted file mode 100644 index c5670d0dc2..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/firebase_project_settings.jpeg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/firebase_project_settings.jpeg deleted file mode 100644 index 4fbc6521c3..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/firebase_project_settings.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/firebase_stream_chat_extension_usage.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/firebase_stream_chat_extension_usage.jpg deleted file mode 100644 index 7374a67f8a..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/firebase_stream_chat_extension_usage.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/hashtag_example.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/hashtag_example.jpg deleted file mode 100644 index a2bb3ba4c9..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/hashtag_example.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/install_stream_chat_firebase_extension.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/install_stream_chat_firebase_extension.jpg deleted file mode 100644 index 309ecce13c..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/install_stream_chat_firebase_extension.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/live_stream_1.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/live_stream_1.jpg deleted file mode 100644 index bef68c6edb..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/live_stream_1.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/live_stream_2.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/live_stream_2.jpg deleted file mode 100644 index 02a3513297..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/live_stream_2.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/localization_support.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/localization_support.jpg deleted file mode 100644 index 50d8b761ee..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/localization_support.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/location_sharing_example.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/location_sharing_example.jpg deleted file mode 100644 index 7f220379c9..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/location_sharing_example.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/location_sharing_example_message.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/location_sharing_example_message.jpg deleted file mode 100644 index 707f138876..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/location_sharing_example_message.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/location_sharing_example_message_thumbnail.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/location_sharing_example_message_thumbnail.jpg deleted file mode 100644 index e2b7d624f5..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/location_sharing_example_message_thumbnail.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/mac_os_split.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/mac_os_split.png deleted file mode 100644 index 7861d54c01..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/mac_os_split.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_actions.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_actions.jpg deleted file mode 100644 index dcfba64ec2..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_actions.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_input.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_input.png deleted file mode 100644 index d63cfbb3e2..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_input.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_input_change_position.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_input_change_position.png deleted file mode 100644 index 859107d25b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_input_change_position.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_input_quoted_message.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_input_quoted_message.png deleted file mode 100644 index c1fda2237b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_input_quoted_message.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_list_view.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_list_view.png deleted file mode 100644 index cc27be3c9b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_list_view_pin.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_list_view_pin.png deleted file mode 100644 index 0b6f1c391f..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_list_view_pin.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_list_view_threads.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_list_view_threads.png deleted file mode 100644 index 2c9387663f..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_list_view_threads.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_reaction_theming.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_reaction_theming.png deleted file mode 100644 index 8cddd6ba22..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_reaction_theming.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_rounded_avatar.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_rounded_avatar.png deleted file mode 100644 index ec3733443a..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_rounded_avatar.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_search_list_view.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_search_list_view.png deleted file mode 100644 index b13f5bdc95..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_search_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_styles.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_styles.png deleted file mode 100644 index db04865c05..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_styles.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_theming.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_theming.png deleted file mode 100644 index b5d28dde0a..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_theming.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_widget_actions.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_widget_actions.png deleted file mode 100644 index e835a4ed04..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/message_widget_actions.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/sdk_title.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/sdk_title.png deleted file mode 100644 index 4d92e89142..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/sdk_title.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/server_key.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/server_key.png deleted file mode 100644 index f11d6fb56b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/server_key.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/slidable_demo.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/slidable_demo.jpg deleted file mode 100644 index 4cbda5d738..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/slidable_demo.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/stream_chat_app_access_keys.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/stream_chat_app_access_keys.jpg deleted file mode 100644 index 1a869cc810..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/stream_chat_app_access_keys.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/stream_chat_user_database.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/stream_chat_user_database.jpg deleted file mode 100644 index fcfe73c82c..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/stream_chat_user_database.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/stream_firebase_extension_configuration.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/stream_firebase_extension_configuration.jpg deleted file mode 100644 index 0c2129319c..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/stream_firebase_extension_configuration.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/swipe_channel.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/swipe_channel.png deleted file mode 100644 index 44f13ca594..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/swipe_channel.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/user_list_view.png b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/user_list_view.png deleted file mode 100644 index 9aede8243d..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/user_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/using_theme.jpg b/docusaurus/flutter_versioned_docs/version-5.x.x/assets/using_theme.jpg deleted file mode 100644 index b835d9316d..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-5.x.x/assets/using_theme.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/01-basics/installation.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/01-basics/installation.mdx deleted file mode 100644 index 43972c8625..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/01-basics/installation.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: installation -title: Installation ---- - -Choosing The Right Flutter Package - -### Why the SDK is split into different packages - -Different applications need different levels of customization and integration with the Stream Chat SDK. -To do this, the Flutter SDK is split into three different packages which build upon the last and give -varying levels of control to the developer. The higher level packages offer better compatibility out of the -box while the lower level SDKs offer fine grained control. There is also a separate package for persistence -which allows you persist data locally which works with all packages. - -### How do I choose? - -#### The case for `stream_chat_flutter` - -For the quickest way to integrate Stream Chat with your app, the UI SDK (`stream_chat_flutter`) is the -way to go. `stream_chat_flutter` contains prebuilt components that manage most operations like data -fetching, pagination, sending a message, and more. This ensures you have a nearly out-of-the-box -experience adding chat to your applications. It is also possible to use this in conjunction with -lower level operations of the SDK to get the best of both worlds. - -:::note -The package allows customization of components to a large extent making it easy to tweak the theme -to match your app colors and such. If you require any additional feature or customization, feel free -to request this through our support channels. -::: - -Summary: - -For the quickest and easiest way to add Chat to your app with prebuilt UI components, use `stream_chat_flutter` - - -#### The case for `stream_chat_flutter_core` - -If your application involves UI that does not fit in with the `stream_chat_flutter` components, `stream_chat_flutter_core` -strips away the UI associated with the components and provides the data fetching and manipulation -capabilities while supplying builders for UI. This allows you to implement your own UI and themes -completely independently while not worrying about writing functions for data and pagination. - -Summary: - -For implementing your own custom UI while not having to worry about lower level API calls, use `stream_chat_flutter_core`. - -#### The case for `stream_chat` - -The `stream_chat` package is the Low-level Client (LLC) of Stream Chat in Flutter. This package wraps -the underlying functionality of Stream Chat and allows the most customization in terms of UI, data, -and architecture. - -Summary: - -For the most control over the SDK and dealing with low level calls to the API, use `stream_chat`. - -### Versioning Policy - -All of the Stream Chat packages follow [semantic versioning](https://semver.org/). - -That means that with a version number x.y.z (major.minor.patch): -- When releasing bug fixes (backwards compatible), we make a patch release by changing the z number (ex: 3.6.2 to 3.6.3). A bug fix is defined as an internal change that fixes incorrect behavior. -- When releasing new features or non-critical fixes, we make a minor release by changing the y number (ex: 3.6.2 to 3.7.0). -- When releasing breaking changes (backward incompatible), we make a major release by changing the x number (ex: 3.6.2 to 4.0.0). - -See the [semantic versioning](https://dart.dev/tools/pub/versioning#semantic-versions) section from the Dart docs for more information. - -This versioning policy does not apply to prerelease packages (below major version of 1). See this -[StackOverflow thread](https://stackoverflow.com/questions/66201337/how-do-dart-package-versions-work-how-should-i-version-my-flutter-plugins) -for more information on Dart package versioning. - -Whenever possible, we will add deprecation warnings in preparation for future breaking changes. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/01-basics/introduction.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/01-basics/introduction.mdx deleted file mode 100644 index a618bbeb21..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/01-basics/introduction.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -slug: / -id: introduction -title: Overview ---- -About The Flutter SDK - -![](../assets/sdk_title.png) - -Stream Chat is a service that helps you easily build a full chat experience in your Flutter apps. -We also support a variety of other SDKs. - -This section of the documentation focuses on our Flutter SDK which helps you easily -ship high quality messaging experiences in apps and programs built with the [Flutter toolkit -made by Google](https://flutter.dev). - -The Stream Chat Flutter SDK comprises five different packages to choose from, ranging from ones -giving you complete control to ones that give you a rich out-of-the-box chat experience. - -The packages that make up the Stream Chat SDK are: - -1. Low Level Client (`stream_chat`): a pure Dart package that can be used on any Dart project. -It provides a low-level client to access the Stream Chat service. -2. Core (`stream_chat_flutter_core`): provides business logic to fetch common things required -for integrating Stream Chat into your application. -The core package allows more customisation and hence provides business logic but no UI components. -3. UI (`stream_chat_flutter`): this library includes both a low-level chat SDK and a set of -reusable and customizable UI components. -4. Persistence (`stream_chat_persistence`): provides a persistence client for fetching and -saving chat data locally. -5. Localizations (`stream_chat_localizations`): provides a set of localizations for the SDK. - -We recommend building prototypes using the full UI package, [`stream_chat_flutter`](https://pub.dev/packages/stream_chat_flutter), -since it contains UI widgets already integrated with Stream's API. It is the fastest way to get up -and running using Stream chat in your app. - -The Flutter SDK enables you to build any type of chat or messaging experience for Android, iOS, Web -and Desktop. - -If you're building a very custom UI and would prefer a more lean package, -[`stream_chat_flutter_core`](https://pub.dev/packages/stream_chat_flutter_core) will be suited to this -use case. Core allows you to build custom, expressive UIs while retaining the benefits of our full -Flutter SDK. APIs for accessing and controlling users, sending messages, and so forth are seamlessly integrated -into this package and accessible via providers and builders. - -Before going into the docs, let's take a small detour to look at how the elements of Stream Chat are structured. - -### Basic Structure - -There are two core elements in chat, Users and Channels. -Channels are groups of one or more users that can message each other. -In an app, you need to have a user connected to query channels. - -There is no specific distinction between a chat with only two people and a group chat, -but there is a way to create a unique chat between a certain number of people by creating a distinct channel. - -![](../assets/chat_basics.png) - -In essence, a normal two-person chat would be a distinct channel created with two members (you cannot add or delete members in this channel), whereas a group created with two people would simply be a non distinct channel (possible to add or remove members). - -:::note -It is also possible to add more than two people in a distinct channel which retains the same add/removal properties and resembles the Slack DMs where you can DM one or more people as well. -::: - -In summary, if you were creating a Whatsapp-like app, the first screen would be a list of channels - which on opening would show a list of messages that were sent by the users in the Channel. - -While this is a simplistic overview of the service, the Flutter SDK handles the UI and more time consuming things (media upload, offline storage, theming, etc.) for you. - -Before reading the docs, consider trying our [online API tour](https://getstream.io/chat/get_started/), -it is a nice way to learn how the API works. -It's in-browser so you'll need to use JavaScript but the core concepts are pretty much the same as Dart. - -You may also like to look at the [Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) -which focuses on using the UI package to get Stream Chat integrated into a Flutter app. - -Further sections break down each individual packages and explain several common operations. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/01-customize_message_widget.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/01-customize_message_widget.mdx deleted file mode 100644 index f6d524d96d..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/01-customize_message_widget.mdx +++ /dev/null @@ -1,229 +0,0 @@ ---- -id: customize_message_widget -title: Message ---- - -Customizing Text Messages with the StreamMessageWidget - -### Introduction - -Every application provides a unique look and feel to their own messaging interface including and not -limited to fonts, colors, and shapes. - -This guide details how to customize the `StreamMessageWidget` in the Stream Chat Flutter UI SDK. - -### Building Custom Messages - -This guide goes into detail about the ability to customize the `StreamMessageWidget`. However, if you want -to customize the default `StreamMessageWidget` in the `StreamMessageListView` provided, you can use the `.copyWith()` method -provided inside the `messageBuilder` parameter of the `StreamMessageListView` like this: - -```dart -StreamMessageListView( - messageBuilder: (context, details, messageList, defaultImpl) { - return defaultImpl.copyWith( - ... - ); - }, -), -``` - -### Providing Custom Reaction Icons - -By default the `StreamReactionIcon` widgets provided by the SDK are `love`, `like`, `sad`, `haha`, and `wow`. -However, you can provide your own custom reaction icons by providing a `reactionIcons` parameter to the `StreamChatConfigurationData`. - -```dart -StreamChat( - client: client, - streamChatConfigData: StreamChatConfigurationData( - reactionIcons: [ - StreamReactionIcon( - type: 'custom', - builder: (context, isHighlighted, iconSize) { - return Icon( - Icons.star, - size: iconSize, - color: isHighlighted ? Colors.red : Colors.black, - ); - }, - ), - ] - ), - child: //Your widget here -) -``` - -### Theming - -You can customize the `StreamMessageWidget` using the `StreamChatTheme` class, so that you can change the -message theme at the top instead of creating your own `StreamMessageWidget` at the lower implementation level. - -There are several things you can change in the theme including text styles and colors of various elements. - -You can also set a different theme for the user's own messages and messages received by them. - -:::note -Theming allows you to change minor factors like style while using the widget directly allows you much -more customization such as replacing a certain widget with another. Some things can only be customized -through the widget and not the theme. -::: - -Here is an example: - -```dart -StreamChatThemeData( - - /// Sets theme for user's messages - ownMessageTheme: StreamMessageThemeData( - messageBackgroundColor: colorTheme.textHighEmphasis, - ), - - /// Sets theme for received messages - otherMessageTheme: StreamMessageThemeData( - avatarTheme: StreamAvatarThemeData( - borderRadius: BorderRadius.circular(8), - ), - ), - -) -``` - -![](../../assets/message_theming.png) - -#### Change message text style - -The `StreamMessageWidget` has multiple `Text` widgets that you can manipulate the styles of. The three main -are the actual message text, user name, message links, and the message timestamp. - -```dart -StreamMessageThemeData( - messageTextStyle: TextStyle(...), - createdAtStyle: TextStyle(...), - messageAuthorStyle: TextStyle(...), - messageLinksStyle: TextStyle(...), -) -``` - -![](../../assets/message_styles.png) - -#### Change avatar theme - -You can change the attributes of the avatar (if displayed) using the `avatarTheme` property. - -```dart -StreamMessageThemeData( - avatarTheme: StreamAvatarThemeData( - borderRadius: BorderRadius.circular(8), - ), -) -``` - -![](../../assets/message_rounded_avatar.png) - -#### Changing Reaction theme - -You also customize the reactions attached to every message using the theme. - -```dart -StreamMessageThemeData( - reactionsBackgroundColor: Colors.red, - reactionsBorderColor: Colors.redAccent, - reactionsMaskColor: Colors.pink, -), -``` - -![](../../assets/message_reaction_theming.png) - -### Changing Message Actions - -When a message is long pressed, the `StreamMessageActionsModal` is shown. - -The `StreamMessageWidget` allows showing or hiding some options if you so choose. - -```dart -StreamMessageWidget( - ... - showUsername = true, - showTimestamp = true, - showReactions = true, - showDeleteMessage = true, - showEditMessage = true, - showReplyMessage = true, - showThreadReplyMessage = true, - showResendMessage = true, - showCopyMessage = true, - showFlagButton = true, - showPinButton = true, - showPinHighlight = true, -), -``` - -![](../../assets/message_widget_actions.png) - -### Building attachments - -The `attachmentBuilders` property allows you to build any kind of attachment (inbuilt or custom) -in your own way. While a separate guide is written for this, it is included here because of relevance. - -```dart -class LocationAttachmentBuilder extends StreamAttachmentWidgetBuilder { - @override - bool canHandle( - Message message, - Map> attachments, - ) { - final imageAttachments = attachments['location']; - return imageAttachments != null && imageAttachments.length == 1; - } - - @override - Widget build( - BuildContext context, - Message message, - Map> attachments, - ) { - final attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'], - attachments[0].extraData['longitude'], - ), - ); - - return WrapAttachmentWidget( - attachmentWidget: attachmentWidget, - attachmentShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - ); - } -} - -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - attachmentBuilders: const [ - LocationAttachmentBuilder(), - ], - ); - }, -), -``` - -### Widget Builders - -Some parameters allow you to construct your own widget in place of some elements in the `StreamMessageWidget`. - -These are: -* `userAvatarBuilder` : Allows user to substitute their own widget in place of the user avatar. -* `editMessageInputBuilder` : Allows user to substitute their own widget in place of the input in edit mode. -* `textBuilder` : Allows user to substitute their own widget in place of the text. -* `bottomRowBuilder` : Allows user to substitute their own widget in the bottom of the message when not deleted. -* `deletedBottomRowBuilder` : Allows user to substitute their own widget in the bottom of the message when deleted. - -```dart -StreamMessageWidget( - ... - textBuilder: (context, message) { - // Add your own text implementation here. - }, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/02-customize_text_messages.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/02-customize_text_messages.mdx deleted file mode 100644 index da6071843f..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/02-customize_text_messages.mdx +++ /dev/null @@ -1,162 +0,0 @@ ---- -id: customize_text_messages -title: Message List View ---- - -Customizing Text Messages - -### Introduction - -Every application provides a unique look and feel to their own messaging interface including and not -limited to fonts, colors, and shapes. - -This guide details how to customize message text in the `StreamMessageListView` / `StreamMessageWidget` in the -Stream Chat Flutter UI SDK. - -:::note -This guide is specifically for the `StreamMessageListView` but if you intend to display a `StreamMessageWidget` -separately, follow the same process without the `.copyWith` and use the default constructor instead. -::: - -### Basics of customizing a `StreamMessageWidget` - -First, add a `StreamMessageListView` in the appropriate place where you intend to display messages from a -channel. - -```dart -StreamMessageListView( - ... -) -``` - -Now, we use the `messageBuilder` parameter to build a custom message. The builder function also provides -the default implementation of the `StreamMessageWidget` so that we can change certain aspects of the widget -without redoing all of the default parameters. - -:::note -In earlier versions of the SDK, some `StreamMessageWidget` parameters were exposed directly through the `StreamMessageListView`, -however, this quickly becomes hard to maintain as more parameters and customizations are added to the -`StreamMessageWidget`. Newer version utilise a cleaner interface to change the parameters by supplying a -default message implementation as aforementioned. -::: - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget; - }, -) -``` - -We use `.copyWith()` to customize the widget: - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - ... - ); - }, -) -``` - -### Customizing text - -If you intend to simply change the theme for the text, you need not recreate the whole widget. The -`StreamMessageWidget` has a `messageTheme` parameter that allows you to pass the theme for most aspects -of the message. - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - messageTheme: StreamMessageThemeData( - ... - messageTextStyle: TextStyle(), - ), - ); - }, -) -``` - -If you want to replace the entire text widget in the `StreamMessageWidget`, you can use the `textBuilder` -parameter which provides a builder for creating a widget to substitute the default text.parameter - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - textBuilder: (context, message) { - return Text(message.text ?? ''); - }, - ); - }, -) -``` - -### Adding Hashtags - -To add elements like hashtags, we can override the `textBuilder` in the StreamMessageWidget: - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, messageList, defaultWidget) { - return defaultWidget.copyWith( - textBuilder: (context, message) { - final text = _replaceHashtags(message.text)?.replaceAll('\n', '\\\n'); - final messageTheme = StreamChatTheme.of(context).ownMessageTheme; - - if (text == null) return const SizedBox(); - - return MarkdownBody( - data: text, - onTapLink: ( - String link, - String? href, - String title, - ) { - // Do something with tapped hashtag - }, - styleSheet: MarkdownStyleSheet.fromTheme( - Theme.of(context).copyWith( - textTheme: Theme.of(context).textTheme.apply( - bodyColor: messageTheme.messageTextStyle?.color, - decoration: messageTheme.messageTextStyle?.decoration, - decorationColor: messageTheme.messageTextStyle?.decorationColor, - decorationStyle: messageTheme.messageTextStyle?.decorationStyle, - fontFamily: messageTheme.messageTextStyle?.fontFamily, - ), - ), - ).copyWith( - a: messageTheme.messageLinksStyle, - p: messageTheme.messageTextStyle, - ), - ); - }, - ); - }, -) - -String? _replaceHashtags(String? text) { - if (text == null) return null; - - final exp = RegExp(r"\B#\w\w+"); - String result = text; - exp.allMatches(text).forEach((match){ - text = text!.replaceAll( - '${match.group(0)}', '[${match.group(0)}](${match.group(0)?.replaceAll(' ', '')})'); - }); - return result; -} -``` - -We can replace the hashtags using RegEx and add links for the MarkdownBody which is done here in the -`_replaceHashtags()` function. -Inside the textBuilder, we use the `flutter_markdown` package to build our hashtags as links. - -![](../../assets/hashtag_example.jpg) diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/03-customize_message_actions.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/03-customize_message_actions.mdx deleted file mode 100644 index 865cccb701..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/03-customize_message_actions.mdx +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: customize_message_actions -title: Message Actions ---- - -Customizing Message Actions - -### Introduction - -Message actions pop up in message overlay, when you long-press a message. - -![](../../assets/message_actions.jpg) - -We have provided granular control over these actions. - -By default we render the following message actions: - -* edit message - -* delete message - -* reply - -* thread reply - -* copy message - -* flag message - -* pin message - -* mark unread - -:::note -Edit and delete message are only available on messages sent by the user. -Additionally, pinning a message requires you to add the roles which are allowed to pin messages. -::: - -:::note -Mark unread message is only available on messages sent by other users and only when read events are enabled for the channel. -Additionally, it's not possible to mark messages inside threads as unread. -::: - -### Partially remove some message actions - -For example, if you only want to keep "copy message" and "delete message": -here is how to do it using the `messageBuilder` with our `StreamMessageWidget`. - -```dart -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - showFlagButton: false, - showEditMessage: false, - showCopyMessage: true, - showDeleteMessage: details.isMyMessage, - showReplyMessage: false, - showThreadReplyMessage: false, - showMarkUnreadMessage: false, - ); - }, -) -``` - -### Add a new custom message action - -The SDK also allows you to add new actions into the dialog. - -For example, let's suppose you want to introduce a new message action - "Demo Action": - -We use the `customActions` parameter of the `StreamMessageWidget` to add extra actions. - -```dart -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - customActions: [ - StreamMessageAction( - leading: const Icon(Icons.add), - title: const Text('Demo Action'), - onTap: (message) { - /// Complete action here - }, - ), - ], - ); - }, -) -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/04-adding_custom_attachments.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/04-adding_custom_attachments.mdx deleted file mode 100644 index 2954523b75..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/04-adding_custom_attachments.mdx +++ /dev/null @@ -1,269 +0,0 @@ ---- -id: adding_custom_attachments -title: Attachments ---- - -Adding Your Own Types Of Attachments To A Message - -### Introduction - -Stream Chat supports attachment types like images, video and files by default. You can also add your -own types of attachments through the SDK such as location, audio, etc. - -This involves doing three things: - -1) Rendering the attachment thumbnail in the `StreamMessageInput` - -2) Sending a message with the custom attachment - -3) Rendering the custom message attachment - -To do this, let's check out an example to add location sharing to Stream Chat. - -### Location Sharing - -Let's build an example of location sharing option in the app: - -![](../../assets/location_sharing_example.jpg) - -* Show a "Share Location" button next to StreamMessageInput `Textfield`. - -* When the user presses this button, it should fetch the current location coordinates of the user, and send a message on the channel as follows: - -```dart -Message( - text: 'This is my location', - attachments: [ - Attachment( - uploadState: const UploadState.success(), - type: 'location', - extraData: const { - 'latitude': 'fetched_latitude', - 'longitude': 'fetched_longitude', - }, - ), - ], -) -``` - -For our example, we are going to use [`geolocator`](https://pub.dev/packages/geolocator) library. -Please check their [setup instructions](https://pub.dev/packages/geolocator) on their docs. - -NOTE: If you are testing on iOS simulator, you will need to set some dummy coordinates, as mentioned [here](https://stackoverflow.com/a/31238119/7489541). -Also don't forget to enable "location update" capability in background mode, from XCode. - -On the receiver end, `location` type attachment should be rendered in map view, in the `StreamMessageListView`. -We are going to use [Google Static Maps API](https://developers.google.com/maps/documentation/maps-static/overview) to render the map in the message. -You can use other libraries as well such as [`google_maps_flutter`](https://pub.dev/packages/google_maps_flutter). - -First, we add a button which when clicked fetches and shares location into the `MessageInput`: - -```dart -StreamMessageInput( - actions: [ - InkWell( - child: const Icon( - Icons.location_on, - size: 20, - color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, - ), - onTap: () { - final channel = StreamChannel.of(context).channel; - - _determinePosition().then((value) { - channel.sendMessage( - Message( - text: 'This is my location', - attachments: [ - Attachment( - uploadState: const UploadState.success(), - type: 'location', - extraData: { - 'latitude': value.latitude.toString(), - 'longitude': value.longitude.toString(), - }, - ), - ], - ), - ); - }).catchError((err) { - print('Error getting location!'); - }); - }, - ), - ], -), - -Future _determinePosition() async { - bool serviceEnabled; - LocationPermission permission; - - serviceEnabled = await Geolocator.isLocationServiceEnabled(); - if (!serviceEnabled) { - return Future.error('Location services are disabled.'); - } - - permission = await Geolocator.checkPermission(); - if (permission == LocationPermission.denied) { - permission = await Geolocator.requestPermission(); - if (permission == LocationPermission.deniedForever) { - return Future.error( - 'Location permissions are permanently denied, we cannot request permissions.'); - } - - if (permission == LocationPermission.denied) { - return Future.error( - 'Location permissions are denied'); - } - } - - return await Geolocator.getCurrentPosition(); -} -``` - -Next, we build the Static Maps URL (Add your API key before using the code snippet): - -```dart - String _buildMapAttachment(String lat, String long) { - final url = Uri( - scheme: 'https', - host: 'maps.googleapis.com', - port: 443, - path: '/maps/api/staticmap', - queryParameters: { - 'center': '${lat},${long}', - 'zoom': '15', - 'size': '600x300', - 'maptype': 'roadmap', - 'key': 'YOUR_API_KEY', - 'markers': 'color:red|${lat},${long}' - }); - - return url.toString(); - } -``` - -And then modify the `StreamMessageListView` and tell it how to build a location attachment, using the `messageBuilder` property and copying the default message implementation overriding the `customAttachmentBuilders` property: - -```dart -StreamMessageListView( - messageBuilder: (context, details, messages, defaultMessage) { - return defaultMessage.copyWith( - customAttachmentBuilders: { - 'location': (context, message, attachments) { - final attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'].toString(), - attachments[0].extraData['longitude'].toString(), - ), - ); - - return WrapAttachmentWidget( - attachmentWidget: attachmentWidget, - attachmentShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - ); - } - }, - ); - }, -), -``` - -This gives us the final location attachment: - -![](../../assets/location_sharing_example_message.jpg) - -Additionally, you can also add a thumbnail if a message has a location attachment (unlike in this case, where we sent the message directly). - -To do this, we will: - -1) Add an attachment instead of sending a message - -2) Customize the `StreamMessageInput` - -First, we add the attachment when the location button is clicked: - -```dart - StreamMessageInputController _messageInputController = StreamMessageInputController(); - - StreamMessageInput( - messageInputController: _messageInputController, - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20, - color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, - ), - onTap: () { - _determinePosition().then((value) { - _messageInputController.addAttachment( - Attachment( - uploadState: const UploadState.success(), - type: 'location', - extraData: { - 'latitude': value.latitude.toString(), - 'longitude': value.longitude.toString(), - }, - ), - ); - }).catchError((err) { - print('Error getting location!'); - }); - }, - ), - ], - ), -``` - -After this, we can build the thumbnail: - -```dart -StreamMessageInput( - messageInputController: _messageInputController, - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20, - color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, - ), - onTap: () { - _determinePosition().then((value) { - _messageInputController.addAttachment( - Attachment( - uploadState: const UploadState.success(), - type: 'location', - extraData: { - 'latitude': value.latitude.toString(), - 'longitude': value.longitude.toString(), - }, - ), - ); - }).catchError((err) { - print('Error getting location!'); - }); - }, - ), - ], - mediaAttachmentBuilder: ( - BuildContext context, - Attachment attachment, - ValueSetter? onRemovePressed, - ) { - if (attachment.type == 'location') { - return Image.network( - _buildMapAttachment( - attachment.extraData['latitude'].toString(), - attachment.extraData['longitude'].toString(), - ), - ); - } - return const SizedBox(); - }, -), -``` - -And we can see the thumbnails in the StreamMessageInput: - -![](../../assets/location_sharing_example_message_thumbnail.jpg) diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/05-customize_attachment_picker_modal.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/05-customize_attachment_picker_modal.mdx deleted file mode 100644 index db4cb97b10..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/05-customize_attachment_picker_modal.mdx +++ /dev/null @@ -1,167 +0,0 @@ ---- -id: customize_attachment_picker_modal -title: Attachment Picker Modal ---- - -Customizing the Attachment Picker Modal - -### Introduction - -The Attachment Picker is a modal that allows users to select attachments from their device. -It is generally used when a user taps the attachment button in the [StreamMessageInput](../07-message_composer/stream_message_input.mdx). - -By default, the Attachment Picker provides multiple picker options as per the platform. -- For example, on Mobile, the default options are Camera, Gallery, File, and Video. -- On Web and Desktop, the default options are Image, Video and File. - -### Customizing the Attachment Picker Modal - -The Attachment Picker Modal can be customized by passing the different values to the `showStreamAttachmentPickerModalBottomSheet` function. - -#### Initial Attachments - -The initial attachments can be passed to the Attachment Picker Modal in two ways. - - * By passing the `initialAttachments` parameter. - - ```dart - StreamMessageInputController _messageInputController = - StreamMessageInputController(); - ... - showStreamAttachmentPickerModalBottomSheet( - context: context, - initialAttachments: [ - // Pass the initial attachments to the modal here if any are available already (optional) - ..._messageInputController.attachments, - ], - ); - ``` - - * By creating a new instance of the `AttachmentPickerModalController` and passing it to the `controller` parameter. - - ```dart - final attachmentPickerController = StreamAttachmentPickerController( - initialAttachments: [ - // Pass the initial attachments to the modal here if any are available already (optional) - ...messageInputController.attachments, - ], - - // The `maxAttachmentSize` and `maxAttachmentCount` can also be set while creating a controller. - maxAttachmentSize: 10 * 1024 * 1024, // 10 MB - maxAttachmentCount: 10, // 10 attachments - ); - - showStreamAttachmentPickerModalBottomSheet( - context: context, - controller: attachmentPickerController, - ); - ``` - -#### Custom Attachment Picker Options - -The Attachment Picker Modal provides a default set of options as per the platform. -However, you can also customize the options by passing the `customOptions` parameter. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - customOptions: [ - // Pass the custom attachment picker options here - AttachmentPickerOption( - icon: const Icon(Icons.audiotrack), - supportedTypes: [AttachmentPickerType.audios], - optionViewBuilder: (context, attachmentPickerController) { - return AudioPicker( - onAudioPicked: (audio) async { - await attachmentPickerController.addAttachment(audio); - return Navigator.pop(context, attachmentPickerController.value); - }, - ); - }, - ), - ], - ); - ``` - -#### Attachment thumbnail size - -The size of the attachment thumbnail item shown in the gallery picker can be defined by passing the `attachmentThumbnailSize` parameter. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - attachmentThumbnailSize: const ThumbnailSize.square(600), - ); - ``` - -#### Attachment thumbnail format - -The format of the attachment thumbnail item shown in the gallery picker can be defined by passing the `attachmentThumbnailFormat` parameter. - -Possible values are `ThumbnailFormat.jpeg` and `ThumbnailFormat.png`. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - attachmentThumbnailFormat: ThumbnailFormat.jpeg, - ); - ``` - -#### Attachment thumbnail quality - -The quality of the attachment thumbnail item shown in the gallery picker can be defined by passing the `attachmentThumbnailQuality` parameter. - -Possible values are between 0 and 100. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - attachmentThumbnailQuality: 70, - ); - ``` - -#### Attachment thumbnail scale - -The scale of the attachment thumbnail item shown in the gallery picker can be defined by passing the `attachmentThumbnailScale` parameter. - -For example, if this is 2, it means that there are four image pixels for every one logical pixel, and the image's actual width and height are -double the height and width that should be used when painting the image. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - attachmentThumbnailScale: 2, - ); - ``` - -#### Additional modal bottom sheet parameters - -The `showStreamAttachmentPickerModalBottomSheet` function also accepts the parameters that are available in the `showModalBottomSheet` function. - - ```dart - showStreamAttachmentPickerModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - useRootNavigator: true, - elevation: 4, - isDismissible: true, - clipBehavior: Clip.antiAlias, - barrierColor: Colors.black.withOpacity(0.5), - constraints: const BoxConstraints( - maxHeight: 500, - maxWidth: 500, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(16), - ), - ), - ); - ``` - - - - - - diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/06-autocomplete_triggers.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/06-autocomplete_triggers.mdx deleted file mode 100644 index 0a3d9d309a..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/06-autocomplete_triggers.mdx +++ /dev/null @@ -1,118 +0,0 @@ ---- -id: autocomplete_triggers -title: Autocomplete Triggers ---- - -Adding Custom Autocomplete Triggers - -### Introduction - -The [StreamMessageInput](../07-message_composer/stream_message_input.mdx) widget provides a way to add custom autocomplete triggers using the `StreamMessageInput.customAutocompleteTriggers` property. - -By default we provide autocomplete triggers for mentions and commands, but it's very easy to add your custom ones. - -### Add Emoji Autocomplete Trigger - -To add a custom emoji autocomplete trigger, you must first create an `AutoCompleteOptions` widget. -This widget will be used to show the autocomplete options. - -For this example we're using two external dependencies: - -- [emojis](https://pub.dev/packages/emojis) -- [`substring_highlight`](https://pub.dev/packages/substring_highlight) - -```dart -import 'package:emojis/emoji.dart'; -import 'package:flutter/material.dart'; - -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:substring_highlight/substring_highlight.dart'; - -/// Overlay for displaying emoji that can be used -class StreamEmojiAutocompleteOptions extends StatelessWidget { - /// Constructor for creating a [StreamEmojiAutocompleteOptions] - const StreamEmojiAutocompleteOptions({ - super.key, - required this.query, - this.onEmojiSelected, - }); - - /// Query for searching emoji. - final String query; - - /// Callback called when an emoji is selected. - final ValueSetter? onEmojiSelected; - - @override - Widget build(BuildContext context) { - final emojis = Emoji.all().where((it) { - final normalizedQuery = query.toUpperCase(); - final normalizedShortName = it.shortName.toUpperCase(); - - return normalizedShortName.contains(normalizedQuery); - }); - - if (emojis.isEmpty) return const SizedBox.shrink(); - - return StreamAutocompleteOptions( - options: emojis, - optionBuilder: (context, emoji) { - final themeData = Theme.of(context); - return ListTile( - dense: true, - horizontalTitleGap: 0, - leading: Text( - emoji.char, - style: themeData.textTheme.titleLarge!.copyWith( - fontSize: 24, - ), - ), - title: SubstringHighlight( - text: emoji.shortName, - term: query, - textStyleHighlight: themeData.textTheme.titleLarge!.copyWith( - color: Colors.yellow, - fontSize: 14.5, - fontWeight: FontWeight.bold, - ), - textStyle: themeData.textTheme.titleLarge!.copyWith( - fontSize: 14.5, - ), - ), - onTap: onEmojiSelected == null ? null : () => onEmojiSelected!(emoji), - ); - }, - ); - } -} -``` - -Now it's time to use the `StreamEmojiAutocompleteOptions` widget. - -```dart -StreamMessageInput( - customAutocompleteTriggers: [ - StreamAutocompleteTrigger( - trigger: ':', - minimumRequiredCharacters: 2, - optionsViewBuilder: ( - context, - autocompleteQuery, - messageEditingController, - ) { - final query = autocompleteQuery.query; - return StreamEmojiAutocompleteOptions( - query: query, - onEmojiSelected: (emoji) { - // accepting the autocomplete option. - StreamAutocomplete.of(context).acceptAutocompleteOption( - emoji.char, - keepTrigger: false, - ); - }, - ); - }, - ), - ], -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/07-slidable_channel_list_preview.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/07-slidable_channel_list_preview.mdx deleted file mode 100644 index 38bf429f6c..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/07-slidable_channel_list_preview.mdx +++ /dev/null @@ -1,212 +0,0 @@ ---- -id: slidable_channel_list_preview -title: Channel List Preview ---- - -Slidable Channel List Preview - -### Introduction - -The default slidable behavior within the channel list has been removed in v4 of the Stream Chat Flutter SDK. -This guide will show you how you can easily add this functionality yourself. - -Please see our [full v4 migration guide](../../05-guides/08-migrations/migration_guide_4_0.mdx) if you're migrating from an earlier version of the Stream Chat Flutter SDK. - -![Slidable demo](../../assets/slidable_demo.jpg) - -### Prerequisites - -This guide assumes you are familiar with the Stream Chat SDK. -If you're new to Stream Chat Flutter, we recommend looking at our [getting started tutorial](https://getstream.io/chat/flutter/tutorial/). - -**Dependencies:** - -```dart -dependencies: - flutter: - sdk: flutter - stream_chat_flutter: ^6.0.0 - flutter_slidable: ^3.0.0 -``` - -⚠️ Note: The examples shown in this guide use the above packages and versions. - -### Example Code - Custom Stream Channel Item Builder - -In this example, you are doing a few important things in the ChannelListPage widget. You're: - -- Using the **flutter_slidable** package to easily add slide functionality. -- Passing in the `itemBuilder` argument for the **StreamChannelListView** widget. This gives access to the current **BuildContext**, **Channel**, and **StreamChannelListTile**, and allows you to create, or customize, the stream channel list tiles. -- Returning a Slidable widget with two CustomSlidableAction widgets - to delete a channel and show more options. These widgets come from the flutter_slidable package. -- Adding `onPressed` behaviour to call `showConfirmationBottomSheet` and `showChannelInfoModalBottomSheet`. These methods come from the **`stream_chat_flutter`** package. They have a few different on-tap callbacks you can supply, for example, `onViewInfoTap`. Alternatively, you can create custom dialog screens from scratch. -- Using the **StreamChannelListController** to perform actions, such as, `deleteChannel`. - -```dart -import 'package:flutter/material.dart'; -import 'package:flutter_slidable/flutter_slidable.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -void main() async { - final client = StreamChatClient( - 's2dxdhpxd94g', - ); - - await client.connectUser( - User(id: 'super-band-9'), - '''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''', - ); - - 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: ChannelListPage( - client: client, - ), - ); - } -} - -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: SlidableAutoCloseBehavior( - child: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - itemBuilder: (context, channels, index, tile) { - final channel = channels[index]; - final chatTheme = StreamChatTheme.of(context); - final backgroundColor = chatTheme.colorTheme.inputBg; - final canDeleteChannel = channel.ownCapabilities - .contains(PermissionType.deleteChannel); - return Slidable( - groupTag: 'channels-actions', - endActionPane: ActionPane( - extentRatio: canDeleteChannel ? 0.40 : 0.20, - motion: const BehindMotion(), - children: [ - CustomSlidableAction( - onPressed: (_) { - showChannelInfoModalBottomSheet( - context: context, - channel: channel, - onViewInfoTap: () { - Navigator.pop(context); - // Navigate to info screen - }, - ); - }, - backgroundColor: backgroundColor, - child: const Icon(Icons.more_horiz), - ), - if (canDeleteChannel) - CustomSlidableAction( - backgroundColor: backgroundColor, - child: StreamSvgIcon.delete( - color: chatTheme.colorTheme.accentError, - ), - onPressed: (_) async { - final res = await showConfirmationBottomSheet( - context, - title: 'Delete Conversation', - question: - 'Are you sure you want to delete this conversation?', - okText: 'Delete', - cancelText: 'Cancel', - icon: StreamSvgIcon.delete( - color: chatTheme.colorTheme.accentError, - ), - ); - if (res == true) { - await _controller.deleteChannel(channel); - } - }, - ), - ], - ), - child: tile, - ); - }, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ), - ); -} - -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) => Scaffold( - appBar: const StreamChannelHeader(), - body: Column( - children: const [ - Expanded( - child: StreamMessageListView(), - ), - StreamMessageInput(), - ], - ), - ); -} -``` - -The above is the complete sample, and all you need for a basic implementation. diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/_category_.json b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/_category_.json deleted file mode 100644 index aa154b1968..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/03-custom_widgets/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Customizing Widgets" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/04-channel_list/_category_.json b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/04-channel_list/_category_.json deleted file mode 100644 index 10c9cfefee..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/04-channel_list/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Channel List" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/04-channel_list/stream_channel_grid_view.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/04-channel_list/stream_channel_grid_view.mdx deleted file mode 100644 index 87ad4dc908..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/04-channel_list/stream_channel_grid_view.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: stream_channel_grid_view -title: StreamChannelGridView ---- - -A Widget For Displaying A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelGridView-class.html) - -### Background - -The `StreamChannelGridView` widget allows displaying a list of channels to a user in a `GridView`. - -:::note -Make sure to check the [StreamChannelListView](./stream_channel_list_view.mdx) documentation to know how to show results in a `ListView`. -::: - -### Basic Example - -Here is a basic example of the `StreamChannelGridView` widget. It consists of the main widget itself, a `StreamChannelListController` to control the list of channels and a callback to handle the tap of a channel. - -```dart -class ChannelGridPage extends StatefulWidget { - const ChannelGridPage({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - State createState() => _ChannelGridPageState(); -} - -class _ChannelGridPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelGridView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -This example by default displays the channels that a user is a part of. Now let's look at customizing -the widget. diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/04-channel_list/stream_channel_list_header.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/04-channel_list/stream_channel_list_header.mdx deleted file mode 100644 index b3e2916a4c..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/04-channel_list/stream_channel_list_header.mdx +++ /dev/null @@ -1,117 +0,0 @@ ---- -id: stream_channel_list_header -title: StreamChannelListHeader ---- - -A Header Widget For A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelListHeader-class.html) - -![](../../assets/channel_list_header.png) - -### Background - -A common pattern for most messaging apps is to show a list of Channels (chats) on the first screen -and navigate to an individual one on being clicked. On this first page where the list of channels are -displayed, it is usual to have functionality such as adding a new chat, display the user logged in, etc. - -To encapsulate all of this functionality into one widget, the Flutter SDK contains a `StreamChannelListHeader` -widget which provides these out of the box. - -### Basic Example - -This is a basic example of a page which has a `StreamChannelListView` and a `StreamChannelListHeader` to recreate a -common Channels Page. - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - appBar: const StreamChannelListHeader(), - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -### Customizing Parts Of The Header - -The header works like a `ListTile` widget. - -Use the `titleBuilder`, `subtitle`, `leading`, or `actions` parameters to substitute the widgets for your own. - -```dart -//... -StreamChannelListHeader( - subtitle: Text('My Custom Subtitle'), -), -``` - -![](../../assets/channel_list_header_custom_subtitle.png) - -The `titleBuilder` parameter helps you build different titles depending on the connection state: - -```dart -//... -StreamChannelListHeader( - titleBuilder: (context, status, client) { - switch(status) { - /// Return your title widget - } - }, -), -``` - -### Showing Connection State - -The `StreamChannelListHeader` can also display connection state below the tile which shows the user if they -are connected or offline, etc. on connection events. - -To enable this, use the `showConnectionStateTile` property. - -```dart -//... -StreamChannelListHeader( - showConnectionStateTile: true, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/04-channel_list/stream_channel_list_view.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/04-channel_list/stream_channel_list_view.mdx deleted file mode 100644 index 7912c5f7ed..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/04-channel_list/stream_channel_list_view.mdx +++ /dev/null @@ -1,106 +0,0 @@ ---- -id: stream_channel_list_view -title: StreamChannelListView ---- - -A Widget For Displaying A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelListView-class.html) - -![](../../assets/channel_list_view.png) - -### Background - -Channels are fundamental elements of Stream Chat and constitute shared spaces which allow users to -message each other. - -1:1 conversations and groups are both examples of channels, albeit with some (distinct/non-distinct) -differences. Displaying the list of channels that a user is a part of is a pattern present in most messaging apps. - -The `StreamChannelListView` widget allows displaying a list of channels to a user. By default, this is NOT -ONLY the channels that the user is a part of. This section goes into setting up and using a `StreamChannelListView` -widget. - -:::note -Make sure to check the [StreamChannelListController](../../04-stream_chat_flutter_core/stream_channel_list_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamChannelListView`. -::: - -### Basic Example - -Here is a basic example of the `StreamChannelListView` widget. It consists of the main widget itself, a `StreamChannelListController` to control the list of channels and a callback to handle the tap of a channel. - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -This example by default displays the channels that a user is a part of. Now let's look at customizing -the widget. - -### Customizing the Channel Preview - -A common aspect of the widget needed to be tweaked according to each app is the Channel Preview (the -Channel tile in the list). To do this, we use the `itemBuilder` parameter like this: - -```dart -StreamChannelListView( - ... - itemBuilder: (context, channels, index, defaultTile) { - return ListTile( - tileColor: Colors.amberAccent, - title: Center( - child: StreamChannelName(channel: channels[index]), - ), - ); - }, -), -``` - -Which gives you a new Channel preview in the list: - -![](../../assets/channel_preview.png) diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/06-message_list/_category_.json b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/06-message_list/_category_.json deleted file mode 100644 index c125c49bfb..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/06-message_list/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Message List" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/06-message_list/stream_message_list_view.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/06-message_list/stream_message_list_view.mdx deleted file mode 100644 index c5a8067fb7..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/06-message_list/stream_message_list_view.mdx +++ /dev/null @@ -1,91 +0,0 @@ ---- -id: stream_message_list_view -title: StreamMessageListView ---- - -A Widget For Displaying A List Of Messages - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageListView-class.html) - -![](../../assets/message_list_view.png) - -### Background - -Every channel can contain a list of messages sent by users inside it. The `StreamMessageListView` widget -displays the list of messages inside a particular channel along with possible attachments and -other message attributes (if the message is pinned for example). This sets it apart from the `StreamMessageSearchListView` -which may not contain messages only from a single channel and is used to search for messages across -many. - -### Basic Example - -The `StreamMessageListView` shows the list of messages of the current channel. It has inbuilt support for -common messaging functionality: displaying and editing messages, adding / modifying reactions, support -for quoting messages, pinning messages, and more. - -An example of how you can use the `StreamMessageListView` is: - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: const StreamChannelHeader(), - body: Column( - children: [ - Expanded( - child: StreamMessageListView(), - ), - const StreamMessageInput(), - ], - ), - ); - } -} -``` - -### Enable Threads - -Threads are made of a parent message and replies linked to it. To enable threading, the SDK requires you -to supply a `threadBuilder` which will supply the page when the thread is clicked. - -```dart -StreamMessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, -), -``` - -![](../../assets/message_list_view_threads.png) - -The `StreamMessageListView` itself can render the thread by supplying the `parentMessage` parameter. - -```dart -StreamMessageListView( - parentMessage: parent, -), -``` - -### Building Custom Messages - -You can also supply your own implementation for displaying messages using the `messageBuilder` parameter. - -:::note -To customize the existing implementation, look at the `StreamMessageWidget` documentation instead. -::: - -```dart -StreamMessageListView( - messageBuilder: (context, details, messageList, defaultImpl) { - // Your implementation of the message here - // E.g: return Text(details.message.text ?? ''); - }, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/06-message_list/stream_message_search_grid_view.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/06-message_list/stream_message_search_grid_view.mdx deleted file mode 100644 index 06e6cdea2b..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/06-message_list/stream_message_search_grid_view.mdx +++ /dev/null @@ -1,60 +0,0 @@ ---- -id: stream_message_search_grid_view -title: StreamMessageSearchGridView ---- - -A Widget To Search For Messages Across Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageSearchGridView-class.html) - -### Background - -The `StreamMessageSearchGridView` widget allows displaying a list of searched messages in a `GridView`. - -:::note -Make sure to check the [StreamMessageSearchListView](./stream_message_search_list_view.mdx) documentation to know how to show results in a `ListView`. -::: - -### Basic Example - -```dart -class StreamMessageSearchPage extends StatefulWidget { - const StreamMessageSearchPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _StreamMessageSearchState(); -} - -class _StreamMessageSearchState extends State { - late final _controller = StreamMessageSearchListController( - client: widget.client, - limit: 20, - filter: Filter.in_( - 'members', - [StreamChat.of(context).user!.id], - ), - searchQuery: 'your query here', - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: StreamMessageSearchGridView( - controller: _controller, - itemBuilder: (context, values, index) { - // return your custom widget here - }, - ), - ); -} -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/06-message_list/stream_message_search_list_view.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/06-message_list/stream_message_search_list_view.mdx deleted file mode 100644 index acb97e4e2a..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/06-message_list/stream_message_search_list_view.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -id: stream_message_search_list_view -title: StreamMessageSearchListView ---- - -A Widget To Search For Messages Across Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageSearchListView-class.html) - -![](../../assets/message_search_list_view.png) - -### Background - -Users in Stream Chat can have several channels and it can get hard to remember which channel has the -message they are searching for. As such, there needs to be a way to search for a message across multiple -channels. This is where `StreamMessageSearchListView` comes in. - -:::note -Make sure to check the [StreamMessageSearchListController](../../04-stream_chat_flutter_core/stream_message_search_list_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamMessageSearchListView`. -::: - -### Basic Example - -While the `StreamMessageListView` is tied to a certain `StreamChannel`, a `StreamMessageSearchListView` is not. - -```dart -class StreamMessageSearchPage extends StatefulWidget { - const StreamMessageSearchPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _StreamMessageSearchState(); -} - -class _StreamMessageSearchState extends State { - late final _controller = StreamMessageSearchListController( - client: widget.client, - limit: 20, - filter: Filter.in_( - 'members', - [StreamChat.of(context).user!.id], - ), - searchQuery: 'your query here', - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: StreamMessageSearchListView( - controller: _controller, - ), - ); -} -``` - -### Customize The Result Tiles - -You can use your own widget for the result items using the `itemBuilder` parameter. - -```dart -StreamMessageSearchListView( - // ... - itemBuilder: (context, responses, index, defaultWidget) { - return Text(responses[index].message.text); - }, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/06-message_list/stream_message_widget.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/06-message_list/stream_message_widget.mdx deleted file mode 100644 index e2da047751..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/06-message_list/stream_message_widget.mdx +++ /dev/null @@ -1,99 +0,0 @@ ---- -id: stream_message_widget -title: StreamMessageWidget ---- - -A Widget For Displaying Messages And Attachments - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageWidget-class.html) - -### Background - -There are several things that need to be displayed with text in a message in a modern messaging app: -attachments, highlights if the message is pinned, user avatars of the sender, etc. - -To encapsulate all of this functionality into one widget, the Flutter SDK contains a `StreamMessageWidget` -widget which provides these out of the box. - -### Basic Example (Modifying `StreamMessageWidget` in `StreamMessageListView`) - -Primarily, the `StreamMessageWidget` is used in the `StreamMessageListView`. To customize only a few properties -of the `StreamMessageWidget` without supplying all other properties, the `messageBuilder` builder supplies -a default implementation of the widget for us to modify. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: StreamMessageListView( - messageBuilder: (context, details, messageList, defaultMessageWidget) { - return defaultMessageWidget.copyWith( - showThreadReplyIndicator: false, - ); - }, - ), - ); - } -} -``` - -### Building A Custom Attachment - -When a custom attachment type (location, audio, etc.) is sent, the MessageWidget also needs to know -how to build it. For this purpose, we can use the `customAttachmentBuilders` parameter. - -As an example, if a message has a attachment type 'location', we do: - -```dart -StreamMessageWidget( - //... - customAttachmentBuilders: { - 'location': (context, message, attachments) { - var attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'], - attachments[0].extraData['longitude'], - ), - ); - - return WrapAttachmentWidget( - attachmentWidget: attachmentWidget, - attachmentShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - ); - } - }, -) -``` - -You can also override the builder for existing attachment types like `image` and `video`. - -### Show User Avatar For Messages - -You can decide to show, hide, or remove user avatars of the sender of the message. To do this, set -the `showUserAvatar` property like this: - -```dart -StreamMessageWidget( - //... - showUserAvatar = DisplayWidget.show, -) -``` - -### Reverse the message - -In most cases, `StreamMessageWidget` needs to be a different orientation depending upon if the sender is the -user or someone else. - -For this, we use the `reverse` parameter to change the orientation of the message: - -```dart -StreamMessageWidget( - //... - reverse = true, -) -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/07-message_composer/_category_.json b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/07-message_composer/_category_.json deleted file mode 100644 index d4e78a7ccc..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/07-message_composer/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Message Composer" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/07-message_composer/stream_message_input.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/07-message_composer/stream_message_input.mdx deleted file mode 100644 index f9bbee168c..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/07-message_composer/stream_message_input.mdx +++ /dev/null @@ -1,112 +0,0 @@ ---- -id: stream_message_input -title: StreamMessageInput ---- - -A Widget Dealing With Everything Related To Sending A Message - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMessageInput-class.html) - -![](../../assets/message_input.png) - -### Background - -In Stream Chat, we can send messages in a channel. However, sending a message isn't as simple as adding -a `TextField` and logic for sending a message. It involves additional processes like addition of media, -quoting a message, adding a custom command like a GIF board, and much more. Moreover, most apps also -need to customize the input to match their theme, overall color and structure pattern, etc. - -To do this, we created a `StreamMessageInput` widget which abstracts all expected functionality a modern input -needs - and allows you to use it out of the box. - -### Basic Example - -A `StreamChannel` is required above the widget tree in which the `StreamMessageInput` is rendered since the channel is -where the messages sent actually go. Let's look at a common example of how we could use the `StreamMessageInput`: - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: StreaChannelHeader(), - body: Column( - children: [ - Expanded( - child: StreamMessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, - ), - ), - StreamMessageInput(), - ], - ), - ); - } -} -``` - -It is common to put this widget in the same page of a `StreamMessageListView` as the bottom widget. - -:::note -Make sure to check the [StreamMessageInputController](../../04-stream_chat_flutter_core/stream_message_input_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamMessageInput`. -::: - -### Adding Custom Actions - -By default, the `StreamMessageInput` has two actions: one for attachments and one for commands like Giphy. -To add your own action, we use the `actions` parameter like this: - -```dart -StreamMessageInput( - actions: [ - InkWell( - child: Icon( - Icons.location_on, - size: 20, - color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, - ), - onTap: () { - // Do something here - }, - ), - ], -), -``` - -This will add on your action to the existing ones. - -### Disable Attachments - -To disable attachments being added to the message, set the `disableAttachments` parameter to true. - -```dart -StreamMessageInput( - disableAttachments: true, -), -``` - -### Changing Position Of MessageInput Components - -You can also change the position of the TextField, actions and 'send' button relative to each other. - -To do this, use the `actionsLocation` or `sendButtonLocation` parameters which help you decide the location -of the buttons in the input. - -For example, if we want the actions on the right and the send button inside the TextField, we can do: - -```dart -StreamMessageInput( - sendButtonLocation: SendButtonLocation.inside, - actionsLocation: ActionsLocation.right, -), -``` - -![](../../assets/message_input_change_position.png) diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/08-member_list/_category_.json b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/08-member_list/_category_.json deleted file mode 100644 index 39e93fd5f2..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/08-member_list/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Member List" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/08-member_list/stream_member_grid_view.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/08-member_list/stream_member_grid_view.mdx deleted file mode 100644 index 9115d8448b..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/08-member_list/stream_member_grid_view.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -id: stream_member_grid_view -title: StreamMemberGridView ---- - -A widget for displaying and selecting members in a grid view. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMemberGridView-class.html) - -### Background - -The `StreamMemberGridView` widget allows displaying a list of members in a `GridView`. - -:::note -See the [StreamMemberListView](./stream_member_list_view.mdx) documentation for displaying members in a `ListView`. -::: - -### Basic Example - -```dart -class MemberGridPage extends StatefulWidget { - const MemberGridPage({ - super.key, - required this.client, - }); - - final Channel channel; - - @override - State createState() => _MemberGridPageState(); -} - -class _MemberGridPageState extends State { - late final _controller = StreamMemberListController( - channel: widget.channel, - limit: 25, - filter: Filter.and([ - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamMemberGridView( - controller: _controller, - onMemberTap: (member) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => Scaffold( - body: Center( - child: StreamUserAvatar( - user: member.user!, - ), - ), - ), - ), - ), - ), - ), - ); -} -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/08-member_list/stream_member_list_view.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/08-member_list/stream_member_list_view.mdx deleted file mode 100644 index 0526db800c..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/08-member_list/stream_member_list_view.mdx +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: stream_member_list_view -title: StreamMemberListView ---- - -A widget for displaying and selecting members in a list view. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamMemberListView-class.html) - -### Background - -A list of members is required for many different purposes, for example, showing a list of users in a Channel. The `StreamMemberListView` displays a list of members. - -:::note -Make sure to check the [StreamMemberListController](../../04-stream_chat_flutter_core/stream_member_list_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamMemberListView`. -::: - -### Basic Example - -```dart -class MemberListPage extends StatefulWidget { - const MemberListPage({super.key}); - - @override - State createState() => _MemberListPageState(); -} - -class _MemberListPageState extends State { - late final StreamMemberListController _memberListController = - StreamMemberListController( - channel: StreamChannel.of(context).channel, - limit: 25, - filter: Filter.and( - [Filter.notEqual('id', StreamChat.of(context).currentUser!.id)], - ), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - @override - Widget build(BuildContext context) { - return RefreshIndicator( - onRefresh: () => _memberListController.refresh(), - child: StreamMemberListView( - controller: _memberListController, - ), - ); - } -} -``` - -### Customize The Member Items - -You can use your own widget for the member items using the `itemBuilder` parameter. - -```dart -StreamMemberListView( - // ... - itemBuilder: (context, members, index, defaultWidget) { - return Text(members[index].user!.name); - }, -), -``` - -### Selecting Members - -The `StreamMemberListView` widget allows selecting members in a list. The `defaultWidget` returned can be customized to indicate that it has been selected. - -```dart -Set _selectedMembers = {}; - -StreamMemberListView( - controller: _memberListController, - itemBuilder: (context, members, index, defaultWidget) { - return defaultWidget.copyWith( - selected: _selectedMembers.contains(members[index]), - ); - }, - onMemberTap: (member) { - setState(() { - _selectedMembers.add(member); - }); - }, -); -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/09-user_list/_category_.json b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/09-user_list/_category_.json deleted file mode 100644 index c6715632dc..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/09-user_list/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "User List" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/09-user_list/stream_user_grid_view.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/09-user_list/stream_user_grid_view.mdx deleted file mode 100644 index b858cc4844..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/09-user_list/stream_user_grid_view.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -id: stream_user_grid_view -title: StreamUserGridView ---- - -A Widget For Displaying And Selecting Users - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamUserGridView-class.html) - -### Background - -The `StreamUserGridView` widget allows displaying a list of users in a `GridView`. - -:::note -Make sure to check the [StreamUserListView](./stream_user_list_view.mdx) documentation to know how to show results in a `ListView`. -::: - -### Basic Example - -```dart -class UserGridPage extends StatefulWidget { - const UserGridPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _UserGridPageState(); -} - -class _UserGridPageState extends State { - late final _controller = StreamUserListController( - client: widget.client, - limit: 25, - filter: Filter.and([ - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamUserGridView( - controller: _controller, - onMemberTap: (member) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => Scaffold( - body: Center( - child: StreamUserAvatar( - user: member.user!, - ), - ), - ), - ), - ), - ), - ), - ); -} -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/09-user_list/stream_user_list_view.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/09-user_list/stream_user_list_view.mdx deleted file mode 100644 index d4e1a83eff..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/09-user_list/stream_user_list_view.mdx +++ /dev/null @@ -1,93 +0,0 @@ ---- -id: stream_user_list_view -title: StreamUserListView ---- - -A Widget For Displaying And Selecting Users - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamUserListView-class.html) - -![](../../assets/user_list_view.png) - -### Background - -A list of users is required for many different purposes: showing a list of users in a Channel, -selecting users to add in a channel, etc. The `StreamUserListView` displays a list -of users. - -:::note -Make sure to check the [StreamUserListController](../../04-stream_chat_flutter_core/stream_user_list_controller.mdx) documentation for more information on how to use the controller to manipulate the `StreamUserListView`. -::: - -### Basic Example - -```dart -class UserListPage extends StatefulWidget { - const UserListPage({super.key}); - - @override - State createState() => _UserListPageState(); -} - -class _UserListPageState extends State { - late final StreamUserListController _userListController = - StreamUserListController( - client: StreamChat.of(context).client, - limit: 25, - filter: Filter.and( - [Filter.notEqual('id', StreamChat.of(context).currentUser!.id)], - ), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - @override - Widget build(BuildContext context) { - return RefreshIndicator( - onRefresh: () => _userListController.refresh(), - child: StreamUserListView( - controller: _userListController, - ), - ); - } -} -``` - -### Customize The User Items - -You can use your own widget for the user items using the `itemBuilder` parameter. - -```dart -StreamUsersListView( - // ... - itemBuilder: (context, users, index, defaultWidget) { - return Text(users[index].name); - }, -), -``` - -### Selecting Users - -The `StreamUserListView` widget allows selecting users in a list. The `defaultWidget` returned can be customized to indicate that it has been selected. - -```dart -Set _selectedUsers = {}; - -StreamUserListView( - controller: _userListController, - itemBuilder: (context, users, index, defaultWidget) { - return defaultWidget.copyWith( - selected: _selectedUsers.contains(users[index]), - ); - }, - onUserTap: (user) { - setState(() { - _selectedUsers.add(user); - }); - }, -); -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/getting_started.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/getting_started.mdx deleted file mode 100644 index 1012b9c59a..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/getting_started.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -id: introduction -title: Getting Started ---- - -Understanding The UI Package Of The Flutter SDK - -### What function does `stream_chat_flutter` serve? - -The UI SDK (`stream_chat_flutter`) contains official Flutter components for Stream Chat, a service for building chat applications. - -While the Stream Chat service functions as the messaging backend and the LLC offers a straightforward integration for Flutter apps, our goal was to ensure the quick incorporation of Chat functionality into your application. To further simplify this process, we developed a dedicated UI package. - -The UI package is built on top of the low-level client and the core package and allows you to build a -full fledged app with either the inbuilt components, modify existing components, or easily add widgets -of your own to match your app's style better. - -### Add pub.dev dependency - -First, you need to add the `stream_chat_flutter` dependency to your `pubspec.yaml`. - -You can either run this command: - -```shell -flutter pub add stream_chat_flutter -``` - -OR - -Add this line in the dependencies section of your `pubspec.yaml` after substituting the latest version: - -```yaml -dependencies: - stream_chat_flutter: ^latest_version -``` - -You can find the package details on [pub.dev](https://pub.dev/packages/stream_chat_flutter). - -### Details On Platform Support - -As of v5, the`stream_chat_flutter` package (UI) added support for web, macOS, Windows, and Linux - on top of the original support for Android and iOS. It has, however, been possible to target desktop and web since Flutter added support for these platforms using the `stream_chat_flutter_core` (builder) and `stream_chat` (low-level client) packages - this remains unchanged. - -Please note that Flutter Web may have additional constraints due to not supporting all plugins that Stream Chat relies on. The respective plugin creators will address this over time. - -### Setup - -This section provides setup instructions for the respective platforms. - -#### Android - -The package uses [`photo_manager`](https://pub.dev/packages/photo_manager) to access the device's photo library. Follow [this wiki](https://pub.dev/packages/photo_manager#android-10-q-29) to fulfill the Android requirements. - -#### iOS - -The library uses [flutter file picker plugin](https://github.com/miguelpruivo/flutter_file_picker) to pick -files from the os. Follow [this wiki](https://github.com/miguelpruivo/flutter_file_picker/wiki/Setup#ios) to fulfill iOS requirements. - -Stream Chat also uses the [`video_player`](https://pub.dev/packages/video_player) package to play videos. Follow [this guide](https://pub.dev/packages/video_player#installation) to fulfill the requirements. - -Stream Chat uses the [`image_picker`](https://pub.dev/packages/image_picker) plugin. -Follow [these instructions](https://pub.dev/packages/image_picker#ios) to check the requirements. - -#### Web - -For the web, edit your `index.html` and add the following in the `` tag to allow the SDK to override the right-click behavior: - -```html - -``` - -#### macOS - -For macOS Stream Chat uses the [`file_selector`](https://pub.dev/packages/file_selector#macos) package. Follow [these instructions](https://pub.dev/packages/file_selector#macos) to check the requirements. - -You also need to add the following [entitlements](https://docs.flutter.dev/development/platform-integration/desktop#entitlements-and-the-app-sandbox) to `Release.entitlement` and `DebugProfile.entitlement`: - -```xml -com.apple.security.network.client - -com.apple.security.files.user-selected.read-write - -``` - -Which grants: - -- Internet permission -- File access permission diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/stream_channel_header.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/stream_channel_header.mdx deleted file mode 100644 index 9e22272cc6..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/stream_channel_header.mdx +++ /dev/null @@ -1,83 +0,0 @@ ---- -id: stream_channel_header -title: StreamChannelHeader ---- - -A Widget To Display Common Channel Details - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannelHeader-class.html) - -![](../assets/channel_header.png) - -### Background - -When a user opens a channel, it is helpful to provide context of which channel they are in. This may -be in the form of a channel name or the users in the channel. Along with that, there also needs to be -a way for the user to look at more details of the channel (media, pinned messages, actions, etc.) and -preferably also a way to navigate back to where they came from. - -To encapsulate all of this functionality into one widget, the Flutter SDK contains a `StreamChannelHeader` -widget which provides these out of the box. - -### Basic Example - -Let's just add a `StreamChannelHeader` to a page with a `StreamMessageListView` and a `StreamMessageInput` to display -and send messages. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: const StreamChannelHeader(), - body: Column( - children: [ - Expanded( - child: StreamMessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, - ), - ), - const StreamMessageInput(), - ], - ), - ); - } -} -``` - -### Customizing Parts Of The Header - -The header works like a `ListTile` widget. - -Use the `title`, `subtitle`, `leading`, or `actions` parameters to substitute the widgets for your own. - -```dart -//... -StreamChannelHeader( - title: Text('My Custom Name'), -), -``` - -![](../assets/channel_header_custom_title.png) - -### Showing Connection State - -The `StreamChannelHeader` can also display connection state below the tile which shows the user if they -are connected or offline, etc. on connection events. - -To enable this, use the `showConnectionStateTile` property. - -```dart -//... -StreamChannelHeader( - showConnectionStateTile: true, -), -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/stream_chat_and_theming.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/stream_chat_and_theming.mdx deleted file mode 100644 index 1b04601da9..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/02-stream_chat_flutter/stream_chat_and_theming.mdx +++ /dev/null @@ -1,90 +0,0 @@ ---- -id: stream_chat_and_theming -title: Theming ---- - -Understanding How To Customize Widgets Using `StreamChatTheme` - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChatTheme-class.html) and [here](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChatThemeData-class.html) - -### Background - -Stream's UI SDK makes it easy for developers to add custom styles and attributes to our widgets. Like most Flutter frameworks, Stream exposes a dedicated widget for theming. - -Using `StreamChatTheme`, users can customize most aspects of our UI widgets by setting attributes using `StreamChatThemeData`. - -Similar to the `Theme` and `ThemeData` in Flutter, Stream Chat uses a top level [inherited widget](https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html) to provide theming information throughout your application. This can be optionally set at the top of your application tree or at a localized point in your widget sub-tree. - -If you'd like to customize the look and feel of Stream chat across your entire application, we recommend setting your theme at the top level. Conversely, users can customize specific screens or widgets by wrapping components in a `StreamChatTheme`. - -### A note on Material 3 - -Material 3 is a new design system from Google that Flutter versions >= 3.16.0 are using by default. Stream Chat SDK is using Material 2 by default. If you are using an older version of Flutter, you should be fine, but if you are using a newer version of Flutter, you should know that all components that are lower than `StreamChat` widget will only use Material 2. - -If you are using Material 3 in your app, keep in mind that any widget under StreamChat will use Material 2 by default. You can change it by providing useMaterial3: true to StreamChat widget. - -```dart -StreamChat( - client: client, - useMaterial3: true, - child: child, -) -``` - -> [!WARNING] -> If you set `useMaterial3` to `true`, all components that are lower than `StreamChat` widget will use Material 3 which is **not supported** by our widgets yet. - -### A closer look at StreamChatThemeData - -Looking at the constructor for `StreamChatThemeData`, 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 `ChannelHeader`, `MessageInputs`, etc. have been broken up into smaller theme objects. - -```dart -factory StreamChatThemeData({ - Brightness? brightness, - TextTheme? textTheme, - ColorTheme? colorTheme, - StreamChannelListHeaderThemeData? channelListHeaderTheme, - StreamChannelPreviewThemeData? channelPreviewTheme, - StreamChannelHeaderThemeData? channelHeaderTheme, - StreamMessageThemeData? otherMessageTheme, - StreamMessageThemeData? ownMessageTheme, - StreamMessageInputThemeData? messageInputTheme, - Widget Function(BuildContext, User)? defaultUserImage, - PlaceholderUserImage? placeholderUserImage, - IconThemeData? primaryIconTheme, - List? reactionIcons, - StreamGalleryHeaderThemeData? imageHeaderTheme, - StreamGalleryFooterThemeData? imageFooterTheme, - StreamMessageListViewThemeData? messageListViewTheme, - }); -``` - -### Stream Chat Theme in use - -Let's take a look at customizing widgets using `StreamChatThemeData`. In the example below, we can change the default color theme to yellow and override the channel header's typography and colors. - -```dart -MaterialApp( - builder: (context, child) => StreamChat( - client: client, - streamChatThemeData: StreamChatThemeData( - colorTheme: StreamColorTheme.light( - accentPrimary: const Color(0xffffe072), - ), - channelHeaderTheme: const ChannelHeaderThemeData( - color: const Color(0xffd34646), - titleStyle: TextStyle( - color: Colors.white, - ), - ), - ), - child: child, - ), -); -``` - -We are creating this class at the very top of our widget tree using the `streamChatThemeData` parameter found in the `StreamChat` widget. - -![](../assets/using_theme.jpg) diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/_category_.json b/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/_category_.json deleted file mode 100644 index 0dff101427..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "State & Offline" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/introduction.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/introduction.mdx deleted file mode 100644 index a59faf1017..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/introduction.mdx +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: introduction -title: Introduction ---- - -Understanding The Core Package Of The Flutter SDK - -This package provides business logic to fetch common things required for integrating Stream Chat into your application. -The core package allows more customisation and hence provides business logic but no UI components. -Please use the `stream_chat_flutter` package for the full fledged suite of UI components or `stream_chat` for the low-level client. - -### Background - -In the early days of the Flutter SDK, the SDK was only split into the LLC (`stream_chat`) and -the UI package (`stream_chat_flutter`). With this you could use a fully built interface with the UI package -or a fully custom interface with the LLC. However, we soon recognised the need for a third intermediary -package which made tasks like building and modifying a list of channels or messages easy but without -the complexity of using low level components. The Core package (`stream_chat_flutter_core`) is a manifestation -of the same idea and allows you to build an interface with Stream Chat without having to deal with -low level code and architecture as well as implementing your own theme and UI effortlessly. -Also, it has very few dependencies. - -We will now explore the components of this intermediary package and understand how it helps you build -the experience you want your users to have. - -The package primarily contains a bunch of controller classes. -Controllers are used to handle the business logic of the chat. You can use them together with our UI widgets, or you can even use them to build your own UI. - -* StreamChannelListController -* StreamUserListController -* StreamMessageSearchListController -* StreamMessageInputController -* LazyLoadScrollView -* PagedValueListenableBuilder - -This section goes into the individual core package widgets and their functional use. diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/lazy_load_scroll_view.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/lazy_load_scroll_view.mdx deleted file mode 100644 index ad680bfbc9..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/lazy_load_scroll_view.mdx +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: lazy_load_scroll_view -title: Paging ---- - -A Widget For Building A Paginated List - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/LazyLoadScrollView-class.html) - -### Background - -The `LazyLoadScrollView` is a widget that helps you build a paginated list. -It provides callbacks to notify you when the list has been scrolled to the bottom and when the list has been scrolled to the top and other necessary callbacks. - -#### Callbacks - -* onStartOfPage: called when the list has been scrolled to the top of the page. - -* onEndOfPage: called when the list has been scrolled to the bottom of the page. - -* onPageScrollStart: called when the scroll of the list starts. - -* onPageScrollEnd: called when the scroll of the list ends. - -* onInBetweenOfPage: called when the list is not either at the top nor at the bottom of the page. - -### Basic Example - -Building a paginated list is a very common task. Here is an example of how to use the `LazyLoadScrollView` to build a simple list with pagination. - -```dart -LazyLoadScrollView( - onEndOfPage: _paginateData, - /// The child could be any widget which dispatches [ScrollNotification]s. - /// For example [ListView], [GridView] or [CustomScrollView]. - child: ListView.builder( - itemBuilder: (context, index) => _buildListTile, - ), -) -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/message_list_core.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/message_list_core.mdx deleted file mode 100644 index 7e988c1ae3..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/message_list_core.mdx +++ /dev/null @@ -1,71 +0,0 @@ ---- -id: message_list_core -title: Messages State ---- - -A Widget For Building A List Of Messages - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/MessageListCore-class.html) - -### Background - -The UI SDK of Stream Chat supplies a `MessageListView` class that builds a list of channels fetching -according to the filters and sort order given. However, in some cases, implementing novel UI is necessary -that cannot be done using the customization approaches given in the widget. - -To do this, we extracted the logic required for fetching channels into a 'Core' widget - a widget that -fetches channels in the expected way via the usual parameters but does not supply any UI and instead -exposes builders to build the UI in situations such as loading, empty data, errors, and on data received. - -### Basic Example - -`MessageListCore` is a simplified class that allows fetching a list of -messages while exposing UI builders. - -This allows you to construct your own UI while not having to -worry about the specific logic of fetching messages in a channel. - -A `MessageListController` is used to paginate data. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Column( - children: [ - Expanded( - child: MessageListCore( - emptyBuilder: (context) { - return const Center( - child: Text('Nothing here...'), - ); - }, - loadingBuilder: (context) { - return const Center( - child: CircularProgressIndicator(), - ); - }, - messageListBuilder: (context, list) { - return MessagesPage(list); - }, - errorBuilder: (context, err) { - return const Center( - child: Text('Error'), - ); - }, - ), - ), - ], - ), - ); - } -} -``` - -Make sure to have a `StreamChannel` ancestor in order to provide the -information about the channels. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/paged_value_listenable_builder.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/paged_value_listenable_builder.mdx deleted file mode 100644 index 529c99a47e..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/paged_value_listenable_builder.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -id: paged_value_listenable_builder -title: Synchronize Paging Data ---- - -A Widget Whose Content Stays Synced With A `ValueNotifier` Of Type `PagedValue`. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/PagedValueListenableBuilder-class.html) - -### Background - -Given a `PagedValueNotifier` implementation and a [builder] which builds widgets from -concrete values of `PagedValue`, this class will automatically register itself as a -listener of the [PagedValueNotifier] and call the [builder] with updated values -when the value changes. - -### Basic Example - -```dart -class UserNameValueNotifier extends PagedValueNotifier { - UserNameValueNotifier() : super(const PagedValue.loading()); - - @override - Future doInitialLoad() async { - // Imitating network delay - await Future.delayed(const Duration(seconds: 1)); - value = const PagedValue( - items: ['Sahil', 'Salvatore', 'Reuben'], - - /// Passing the key to load the next page - nextPageKey: nextPageKey, - ); - } - - @override - Future loadMore(int nextPageKey) async { - // Imitating network delay - await Future.delayed(const Duration(seconds: 1)); - final previousItems = value.asSuccess.items; - final newItems = previousItems + ['Deven', 'Sacha', 'Gordon']; - value = PagedValue( - items: newItems, - // Passing nextPageKey as null to indicate - // that there are no more items. - nextPageKey: null, - ); - } -} - -class _MyHomePageState extends State { - final pagedValueNotifier = UserNameValueNotifier(); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Center( - child: PagedValueListenableBuilder( - builder: (context, value, child) { - // This builder will only get called when the _counter - // is updated. - return value.when( - (userNames, nextPageKey, error) => Column( - children: [ - const Text('Usernames:'), - Expanded( - child: ListView( - children: userNames.map(Text.new).toList(), - ), - ), - if (nextPageKey != null) - TextButton( - child: const Text('Load more'), - onPressed: () => pagedValueNotifier.loadMore(nextPageKey), - ), - ], - ), - loading: CircularProgressIndicator.new, - error: (e) => Text('Error: $e'), - ); - }, - valueListenable: pagedValueNotifier, - ), - ), - ); - } -} -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/setup.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/setup.mdx deleted file mode 100644 index f297484274..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/setup.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -id: setup -title: Setup ---- - -Understanding Setup For `stream_chat_flutter_core` - -### Add pub.dev dependency - -First, you need to add the `stream_chat_flutter_core` dependency to your pubspec.yaml - -You can either run this command: - -```shell -flutter pub add stream_chat_flutter_core -``` - -OR - -Add this line in the dependencies section of your pubspec.yaml after substituting latest version: - -```yaml -dependencies: - stream_chat_flutter_core: ^latest_version -``` - -You can find the package details on [pub.dev](https://pub.dev/packages/stream_chat_flutter_core). diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_channel_list_controller.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_channel_list_controller.mdx deleted file mode 100644 index 9ffba46085..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_channel_list_controller.mdx +++ /dev/null @@ -1,152 +0,0 @@ ---- -id: stream_channel_list_controller -title: Channel State & Filtering ---- - -A Widget For Controlling A List Of Channels - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamChannelListController-class.html) - -### Background - -The `StreamChannelListController` is a controller class that allows you to control a list of channels. -`StreamChannelListController` is a required parameter of the `StreamChannelListView` widget. -Check the [`StreamChannelListView` documentation](../02-stream_chat_flutter/04-channel_list/stream_channel_list_view.mdx) to read more about that. - -The `StreamChannelListController` also listens for various events and manipulates the current list of channels accordingly. -Passing a `StreamChannelListEventHandler` to the `StreamChannelListController` will allow you to customize this behaviour. - -### Basic Example - -Building a custom channel list is a very common task. Here is an example of how to use the `StreamChannelListController` to build a simple list with pagination. - -First of all we should create an instance of the `StreamChannelListController` and provide it with the `StreamChatClient` instance. -You can also add a `Filter`, a list of `SortOption`s and other pagination-related parameters. - -```dart -class _MyChannelListPageState extends State { - /// Controller used for loading more data and controlling pagination in - /// [StreamChannelListController]. - late final channelListController = StreamChannelListController( - client: StreamChatCore.of(context).client, - filter: Filter.and([ - Filter.equal('type', 'messaging'), - Filter.in_( - 'members', - [ - StreamChatCore.of(context).currentUser!.id, - ], - ), - ]), - ); - ... -} -``` - -Make sure you call `channelListController.doInitialLoad()` to load the initial data and `channelListController.dispose()` when the controller is no longer required. - -```dart -@override -void initState() { - channelListController.doInitialLoad(); - super.initState(); -} - -@override -void dispose() { - channelListController.dispose(); - super.dispose(); -} -``` - -The `StreamChannelListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of channels has changed. -You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest channels. - -```dart -@override -Widget build(BuildContext context) => Scaffold( - body: PagedValueListenableBuilder( - valueListenable: channelListController, - builder: (context, value, child) { - return value.when( - (channels, nextPageKey, error) => LazyLoadScrollView( - onEndOfPage: () async { - if (nextPageKey != null) { - channelListController.loadMore(nextPageKey); - } - }, - child: ListView.builder( - /// We're using the channels length when there are no more - /// pages to load and there are no errors with pagination. - /// In case we need to show a loading indicator or and error - /// tile we're increasing the count by 1. - itemCount: (nextPageKey != null || error != null) - ? channels.length + 1 - : channels.length, - itemBuilder: (BuildContext context, int index) { - if (index == channels.length) { - if (error != null) { - return TextButton( - onPressed: () { - channelListController.retry(); - }, - child: Text(error.message), - ); - } - return const CircularProgressIndicator(); - } - - final _item = channels[index]; - return ListTile( - title: Text(_item.name ?? ''), - subtitle: StreamBuilder( - stream: _item.state!.lastMessageStream, - initialData: _item.state!.lastMessage, - builder: (context, snapshot) { - if (snapshot.hasData) { - return Text(snapshot.data!.text!); - } - - return const SizedBox(); - }, - ), - onTap: () { - /// Display a list of messages when the user taps on - /// an item. We can use [StreamChannel] to wrap our - /// [MessageScreen] screen with the selected channel. - /// - /// This allows us to use a built-in inherited widget - /// for accessing our `channel` later on. - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: _item, - child: const MessageScreen(), - ), - ), - ); - }, - ); - }, - ), - ), - loading: () => const Center( - child: SizedBox( - height: 100, - width: 100, - child: CircularProgressIndicator(), - ), - ), - error: (e) => Center( - child: Text( - 'Oh no, something went wrong. ' - 'Please check your config. $e', - ), - ), - ); - }, - ), - ); -``` - -In this case we're using the [`LazyLoadScrollView`](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_channel_list_event_handler.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_channel_list_event_handler.mdx deleted file mode 100644 index ee525d8d63..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_channel_list_event_handler.mdx +++ /dev/null @@ -1,54 +0,0 @@ ---- -id: stream_channel_list_event_handler -title: Channels Events ---- - -A Class To Customize The Event Handler For The StreamChannelListController. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamChannelListEventHandler-class.html) - -### Background - -A `StreamChannelListEventHandler` is a class that handles the events that are related to the channel list loaded by `StreamChannelListController`. -The `StreamChannelListController` automatically creates a `StreamChannelListEventHandler` internally and handles the events. In order to provide a custom -implementation of `StreamChannelListEventHandler`, you need to create a class that extends the `StreamChannelListEventHandler` class. - -### Basic Example - -There are 2 ways to provide a custom implementation of `StreamChannelListEventHandler`: - -* Create a class that extends the `StreamChannelListEventHandler` and pass it down to the controller. - -```dart -class MyCustomEventHandler extends StreamChannelListEventHandler { - @override - void onConnectionRecovered( - Event event, - StreamChannelListController controller, - ) { - // Write your own custom implementation here - } -} -``` - -Pass it down to the controller: - -```dart - late final listController = StreamChannelListController( - client: StreamChat.of(context).client, - eventHandler: MyCustomEventHandler(), - ); -``` - -* Mix the `StreamChannelListEventHandler` into your widget state. - -```dart -class _ChannelListPageState extends State { - - late final _listController = StreamChannelListController( - client: StreamChat.of(context).client, - eventHandler: MyCustomEventHandler(), - ); -} -``` - diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_chat_core.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_chat_core.mdx deleted file mode 100644 index fb68fa1dea..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_chat_core.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -id: stream_chat_core -title: Chat Client ---- - -`StreamChatCore` is a version of `StreamChat` found in `stream_chat_flutter` that is decoupled from -theme and initialisations. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamChatCore-class.html) - -`StreamChatCore` is used to provide information about the chat client to the widget tree. -This Widget is used to react to life cycle changes and system updates. -When the app goes into the background, the web socket connection is automatically closed and when it goes back to foreground the connection is opened again. - -Like the `StreamChat` widget in the higher level UI package, the `StreamChatCore` widget should -be on the top level before using any Stream functionality: - -```dart -return MaterialApp( - title: 'Stream Chat Core Example', - home: HomeScreen(), - builder: (context, child) => StreamChatCore( - client: client, - child: child, - ), - ); -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_member_list_controller.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_member_list_controller.mdx deleted file mode 100644 index 192cf13878..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_member_list_controller.mdx +++ /dev/null @@ -1,111 +0,0 @@ ---- -id: stream_member_list_controller -title: Members State ---- - -A widget for controlling a list of members. - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamMemberListController-class.html) - -### Background - -The `StreamMemberListController` is a controller class that allows you to control a list of users. -`StreamMemberListController` is a required parameter of the `StreamMemberListView` widget. -Check the [`StreamMemberListView` documentation](../02-stream_chat_flutter/04-channel_list/stream_channel_list_view.mdx) to read more about that. - -### Basic Example - -Building a custom member list is a very common task. Here is an example of how to use the `StreamMemberListController` to build a simple list with pagination. - -First, create an instance of the `StreamMemberListController` and provide it with the `StreamChatClient` instance. -You can also add a `Filter`, a list of `SortOption`s, and other pagination-related parameters. - -```dart -class MemberListPageState extends State { - /// Controller used for loading more data and controlling pagination in - /// [StreamMemberListController]. - late final memberListController = StreamMemberListController( - channel: StreamChannel.of(context).channel, - ); -``` - -Make sure you call `memberListController.doInitialLoad()` to load the initial data and `memberListController.dispose()` when the controller is no longer required. - -```dart -@override -void initState() { - memberListController.doInitialLoad(); - super.initState(); -} - -@override -void dispose() { - memberListController.dispose(); - super.dispose(); -} -``` - -The `StreamMemberListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of members has changed. -You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest members. - -```dart -@override -Widget build(BuildContext context) => Scaffold( - body: PagedValueListenableBuilder( - valueListenable: memberListController, - builder: (context, value, child) { - return value.when( - (members, nextPageKey, error) => LazyLoadScrollView( - onEndOfPage: () async { - if (nextPageKey != null) { - memberListController.loadMore(nextPageKey); - } - }, - child: ListView.builder( - /// We're using the members length when there are no more - /// pages to load and there are no errors with pagination. - /// In case we need to show a loading indicator or and error - /// tile we're increasing the count by 1. - itemCount: (nextPageKey != null || error != null) - ? members.length + 1 - : members.length, - itemBuilder: (BuildContext context, int index) { - if (index == members.length) { - if (error != null) { - return TextButton( - onPressed: () { - memberListController.retry(); - }, - child: Text(error.message), - ); - } - return const CircularProgressIndicator(); - } - - final _item = members[index]; - return ListTile( - title: Text(_item.user?.name ?? ''), - ); - }, - ), - ), - loading: () => const Center( - child: SizedBox( - height: 100, - width: 100, - child: CircularProgressIndicator(), - ), - ), - error: (e) => Center( - child: Text( - 'Oh no, something went wrong. ' - 'Please check your config. $e', - ), - ), - ); - }, - ), - ); -``` - -In this case, we're using the [LazyLoadScrollView](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list. diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_message_input_controller.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_message_input_controller.mdx deleted file mode 100644 index 94e2b2561a..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_message_input_controller.mdx +++ /dev/null @@ -1,88 +0,0 @@ ---- -id: stream_message_input_controller -title: Message Composer State ---- - -A Widget For Controlling A Message Input - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamMessageInputController-class.html) - -### Background - -The `StreamMessageInputController` is a controller class that embed the business logic to compose a message. -`StreamMessageInputController` is a parameter of the `StreamMessageInput` widget. -Check the [`StreamMessageInput` documentation](../02-stream_chat_flutter/07-message_composer/stream_message_input.mdx) to read more about that. - -### Basic Example - -Building a custom message input is a common task. Here is an example of how to use the `StreamMessageInputController` to build a simple custom message input widget. - -First of all we should create an instance of the `StreamMessageInputController`. - -```dart -class MessageScreenState extends State { - final StreamMessageInputController messageInputController = StreamMessageInputController(); -``` - -Make sure you call `messageInputController.dispose()` when the controller is no longer required. - -```dart -@override -void dispose() { - messageInputController.dispose(); - super.dispose(); -} -``` - -The `StreamMessageInputController` is basically a `ValueNotifier` that notifies you when the message being composed has changed. -You can use a `ValueListenableBuilder` to build your UI depending on the latest message. -For a very simple message input you could even pass the `messageInputController.textEditingController` to your `TextField` and set the `onChanged` callback. - -```dart -... -Padding( - padding: const EdgeInsets.all(8), - child: Row( - children: [ - Expanded( - child: TextField( - controller: messageInputController.textFieldController, - onChanged: (s) => messageInputController.text = s, - decoration: const InputDecoration( - hintText: 'Enter your message', - ), - ), - ), - Material( - type: MaterialType.circle, - color: Colors.blue, - clipBehavior: Clip.hardEdge, - child: InkWell( - onTap: () async { - if (messageInputController.message.text?.isNotEmpty == - true) { - await channel.sendMessage( - messageInputController.message, - ); - messageInputController.clear(); - if (context.mounted) { - _updateList(); - } - } - }, - child: const Padding( - padding: EdgeInsets.all(8), - child: Center( - child: Icon( - Icons.send, - color: Colors.white, - ), - ), - ), - ), - ), - ], - ), -), -... -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_message_search_list_controller.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_message_search_list_controller.mdx deleted file mode 100644 index fe572c5c11..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_message_search_list_controller.mdx +++ /dev/null @@ -1,126 +0,0 @@ ---- -id: stream_message_search_list_controller -title: Message Search State ---- - -A Widget For Controlling A List Of Searched Messages - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamMessageSearchListController-class.html) - -### Background - -The `StreamMessageSearchListController` is a controller class that allows you to control a list of searched messages. -`StreamMessageSearchListController` is a required parameter of the `StreamMessageSearchListView` widget. -Check the [`StreamMessageSearchListView` documentation](../02-stream_chat_flutter/06-message_list/stream_message_search_list_view.mdx) to read more about that. - -### Basic Example - -Building a custom message search feature is a common task. Here is an example of how to use the `StreamMessageSearchListController` to build a simple search list with pagination. - -First of all we should create an instance of the `StreamMessageSearchListController` and provide it with the `StreamChatClient` instance. -You can also add a `Filter`, a list of `SortOption`s and other pagination-related parameters. - -```dart -class SearchListPageState extends State { - /// Controller used for loading more data and controlling pagination in - /// [StreamMessageSearchListController]. - late final messageSearchListController = StreamMessageSearchListController( - client: StreamChatCore.of(context).client, - ); -``` - -Make sure you call `messageSearchListController.doInitialLoad()` to load the initial data and `messageSearchListController.dispose()` when the controller is no longer required. - -```dart -@override -void initState() { - messageSearchListController.doInitialLoad(); - super.initState(); -} - -@override -void dispose() { - messageSearchListController.dispose(); - super.dispose(); -} -``` - -The `StreamMessageSearchListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of responses has changed. -You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest responses. - -```dart -@override -Widget build(BuildContext context) => Scaffold( - body: Column( - children: [ - TextField( - /// This is just a sample implementation of a search field. - /// In a real-world app you should throttle the search requests. - /// You can use our library [rate_limiter](https://pub.dev/packages/rate_limiter). - onChanged: (s) { - messageSearchListController..searchQuery = s..doInitialLoad(); - }, - ), - Expanded( - child: PagedValueListenableBuilder( - valueListenable: messageSearchListController, - builder: (context, value, child) { - return value.when( - (responses, nextPageKey, error) => LazyLoadScrollView( - onEndOfPage: () async { - if (nextPageKey != null) { - messageSearchListController.loadMore(nextPageKey); - } - }, - child: ListView.builder( - /// We're using the responses length when there are no more - /// pages to load and there are no errors with pagination. - /// In case we need to show a loading indicator or and error - /// tile we're increasing the count by 1. - itemCount: (nextPageKey != null || error != null) - ? responses.length + 1 - : responses.length, - itemBuilder: (BuildContext context, int index) { - if (index == responses.length) { - if (error != null) { - return TextButton( - onPressed: () { - messageSearchListController.retry(); - }, - child: Text(error.message), - ); - } - return const CircularProgressIndicator(); - } - - final _item = responses[index]; - return ListTile( - title: Text(_item.channel?.name ?? ''), - subtitle: Text(_item.message.text ?? ''), - ); - }, - ), - ), - loading: () => const Center( - child: SizedBox( - height: 100, - width: 100, - child: CircularProgressIndicator(), - ), - ), - error: (e) => Center( - child: Text( - 'Oh no, something went wrong. ' - 'Please check your config. $e', - ), - ), - ); - }, - ), - ), - ], - ), - ); -``` - -In this case we're using the [`LazyLoadScrollView`](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_user_list_controller.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_user_list_controller.mdx deleted file mode 100644 index 7ce1d9a7fc..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/04-stream_chat_flutter_core/stream_user_list_controller.mdx +++ /dev/null @@ -1,111 +0,0 @@ ---- -id: stream_user_list_controller -title: Users State & Filtering ---- - -A Widget For Controlling A List Of Users - -Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamUserListController-class.html) - -### Background - -The `StreamUserListController` is a controller class that allows you to control a list of users. -`StreamUserListController` is a required parameter of the `StreamUserListView` widget. -Check the [`StreamUserListView` documentation](../02-stream_chat_flutter/09-user_list/stream_user_list_view.mdx) to read more about that. - -### Basic Example - -Building a custom user list is a very common task. Here is an example of how to use the `StreamUserListController` to build a simple list with pagination. - -First of all we should create an instance of the `StreamUserListController` and provide it with the `StreamChatClient` instance. -You can also add a `Filter`, a list of `SortOption`s and other pagination-related parameters. - -```dart -class UserListPageState extends State { - /// Controller used for loading more data and controlling pagination in - /// [StreamUserListController]. - late final userListController = StreamUserListController( - client: StreamChatCore.of(context).client, - ); -``` - -Make sure you call `userListController.doInitialLoad()` to load the initial data and `userListController.dispose()` when the controller is no longer required. - -```dart -@override -void initState() { - userListController.doInitialLoad(); - super.initState(); -} - -@override -void dispose() { - userListController.dispose(); - super.dispose(); -} -``` - -The `StreamUserListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of users has changed. -You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest users. - -```dart -@override -Widget build(BuildContext context) => Scaffold( - body: PagedValueListenableBuilder( - valueListenable: userListController, - builder: (context, value, child) { - return value.when( - (users, nextPageKey, error) => LazyLoadScrollView( - onEndOfPage: () async { - if (nextPageKey != null) { - userListController.loadMore(nextPageKey); - } - }, - child: ListView.builder( - /// We're using the users length when there are no more - /// pages to load and there are no errors with pagination. - /// In case we need to show a loading indicator or and error - /// tile we're increasing the count by 1. - itemCount: (nextPageKey != null || error != null) - ? users.length + 1 - : users.length, - itemBuilder: (BuildContext context, int index) { - if (index == users.length) { - if (error != null) { - return TextButton( - onPressed: () { - userListController.retry(); - }, - child: Text(error.message), - ); - } - return const CircularProgressIndicator(); - } - - final _item = users[index]; - return ListTile( - title: Text(_item.name), - ); - }, - ), - ), - loading: () => const Center( - child: SizedBox( - height: 100, - width: 100, - child: CircularProgressIndicator(), - ), - ), - error: (e) => Center( - child: Text( - 'Oh no, something went wrong. ' - 'Please check your config. $e', - ), - ), - ); - }, - ), - ); -``` - -In this case we're using the [`LazyLoadScrollView`](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/01-understanding_filters.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/01-understanding_filters.mdx deleted file mode 100644 index 152a8a8fee..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/01-understanding_filters.mdx +++ /dev/null @@ -1,193 +0,0 @@ ---- -id: understanding_filters -title: Filters ---- - -Understanding Filters - -### Introduction - -Filters are used to get a specific subset of objects (channels, users, messages, members, etc) which -fit the conditions specified. Earlier versions of the SDK contained String-based filters which are now replaced by type-safe -filters. This guide aims to explain the different types of filters and how to use them. - -### Types Of Filters - -#### Filter.equal - -The 'equal' filter gets the objects where the given key has the specified value. - -```dart -Filter.equal('type', 'messaging'), -``` - -#### Filter.notEqual - -The `notEqual` filter gets the objects where the given key does not have the specified value. - -```dart -Filter.notEqual('type', 'messaging'), -``` - -#### Filter.greater - -The 'greater' filter gets the objects where the given key has a higher value than the specified value. - -```dart -Filter.greater('count', 5), -``` - -#### Filter.greaterOrEqual - -The 'greaterOrEqual' filter gets the objects where the given key has an equal or higher value than the specified value. - -```dart -Filter.greaterOrEqual('count', 5), -``` - -#### Filter.less - -The 'less' filter gets the objects where the given key has a lesser value than the specified value. - -```dart -Filter.less('count', 5), -``` - -#### Filter.lessOrEqual - -The 'lessOrEqual' filter gets the objects where the given key has a lesser or equal value than the specified value. - -```dart -Filter.lessOrEqual('count', 5), -``` - -#### Filter.in_ - -The `in_` filter allows getting objects where the key matches any in a specified array. - -```dart -Filter.in_('members', [user.id]) -``` - -:::note -Since 'in' is a keyword in Dart, the filter has an underscore added. This does not apply to the `notIn` -keyword. -::: - -#### Filter.notIn - -The `notIn` filter allows getting objects where the key matches none in a specified array. - -```dart -Filter.notIn('members', [user.id]) -``` - -#### Filter.query - -The 'query' filter matches values by performing text search with the specified value. - -```dart -Filter.query('name', 'demo') -``` - -#### Filter.autoComplete - -The 'autoComplete' filter matches values with the specified prefix. - -```dart -Filter.autoComplete('name', 'demo') -``` - -#### Filter.exists - -The 'exists' filter matches values that exist, or don't exist, based on the specified boolean value. - -```dart -Filter.exists('name') -``` - -#### Filter.notExists - -The `notExists` filter checks if the specified key doesn't exist. This is a simplified call to `Filter.exists` -with the value set to false. - -```dart -Filter.notExists('name') -``` - -#### Filter.contains - -The 'contains' filter matches any list that contains the specified value. - -```dart -Filter.contains('teams', 'red') -``` - -#### Filter.empty - -The 'empty' filter constructor returns an empty filter. It's the equivalent of an empty map `{}`; - -```dart -Filter.empty(); -``` - -#### Filter.raw - -The 'raw' filter constructor lets you specify a raw filter. We suggest using this only if you can't manage to build what you want using the other constructors. - -```dart -Filter.raw(value: { - 'members': [ - ..._selectedUsers.map((e) => e.id), - chatState.currentUser!.id, - ], - 'distinct': true, -}); -``` - -#### Filter.custom - -The 'custom' filter is used to create a custom filter in case it does not exists or it's not been added to the SDK yet. -Note that the filter must be supported by the Stream backend in order to work. - -```dart -Filter.custom( - operator: '\$max', - value: 10, -) -``` - -### Group Queries - -#### Filter.and - -The 'and' operator combines multiple queries. - -```dart -final filter = Filter.and([ - Filter.equal('type', 'messaging'), - Filter.in_('members', [user.id]) -]) -``` - -#### Filter.or - -Combines the provided filters and matches the values matched by at least one of the filters. - -```dart -final filter = Filter.or([ - Filter.in_('bannedUsers', [user.id]), - Filter.in_('shadowBannedUsers', [user.id]) -]) -``` - -#### Filter.nor - -Combines the provided filters and matches the values not matched by all the filters. - -```dart -final filter = Filter.nor([ - Filter.in_('bannedUsers', [user.id]), - Filter.in_('shadowBannedUsers', [user.id]) -]) -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/02-adding_local_data_persistence.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/02-adding_local_data_persistence.mdx deleted file mode 100644 index 3943b1f972..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/02-adding_local_data_persistence.mdx +++ /dev/null @@ -1,75 +0,0 @@ ---- -id: adding_local_data_persistence -title: Offline Support ---- - -Adding Local Data Persistence for Offline Support - -### Introduction - -Most messaging apps need to work regardless of whether the app is currently connected to the internet. -Local data persistence stores the fetched data from the backend on a local SQLite database using the -moor package in Flutter. All packages in the SDK can use local data persistence to store messages -across multiple platforms. - -### Implementation - -To add data persistence you can extend the class ChatPersistenceClient and pass an instance to the StreamChatClient. - -```dart -class CustomChatPersistentClient extends ChatPersistenceClient { -... -} - -final client = StreamChatClient( - apiKey ?? kDefaultStreamApiKey, - logLevel: Level.INFO, -)..chatPersistenceClient = CustomChatPersistentClient(); -``` - -We provide an official persistent client in the [`stream_chat_persistence`](https://pub.dev/packages/stream_chat_persistence) -package that works using the library [moor](https://moor.simonbinder.eu), an SQLite ORM. - -Add this to your package's `pubspec.yaml` file, using the latest version. - -```yaml -dependencies: - stream_chat_persistence: ^latest_version -``` - -You should then run `flutter packages get` - -The usage is pretty simple. - -1. Create a new instance of `StreamChatPersistenceClient` providing `logLevel` and `connectionMode` - -```dart -final chatPersistentClient = StreamChatPersistenceClient( - logLevel: Level.INFO, - connectionMode: ConnectionMode.background, -); -``` - -2. Pass the instance to the official `StreamChatClient` - -```dart - final client = StreamChatClient( - apiKey ?? kDefaultStreamApiKey, - logLevel: Level.INFO, - )..chatPersistenceClient = chatPersistentClient; -``` - -And you are ready to go... - -Note that passing `ConnectionMode.background` the database uses a background isolate to unblock the main thread. -The `StreamChatClient` uses the `chatPersistentClient` to synchronize the database with the newest -information every time it receives new data about channels/messages/users. - -### Multi-user - -The DB file is named after the `userId`, so if you instantiate a client using a different `userId` you will use a different database. -Calling `client.disconnectUser(flushChatPersistence: true)` flushes all current database data. - -### Updating/deleting/sending a message while offline - -The information about the action is saved in offline storage. When the client returns online, everything is retried. diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/03-user_token_generation_with_firebase_auth.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/03-user_token_generation_with_firebase_auth.mdx deleted file mode 100644 index 4292f7fb09..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/03-user_token_generation_with_firebase_auth.mdx +++ /dev/null @@ -1,454 +0,0 @@ ---- -id: token_generation_with_firebase -title: Authentication ---- - -Securely generate Stream Chat user tokens using Firebase Authentication and Cloud Functions. - -:::note -This guide assumes that you are familiar with Firebase Authentication and Cloud Functions for Flutter and using the Flutter Stream Chat SDK. -::: - -### Introduction - -In this guide, you'll explore how you can use Firebase Auth as an authentication provider and create Firebase Cloud functions to securely -generate Stream Chat user tokens. - -You will use Stream's [NodeJS client](https://getstream.io/chat/docs/node/?language=javascript) for Stream account creation and -token generation, and [Flutter Cloud Functions for Firebase](https://firebase.google.com/docs/functions/callable?gen=2nd#dart) to invoke the cloud functions -from your Flutter app. - -Stream supports several different [backend clients](https://getstream.io/chat/sdk/#backend-clients) to integrate with your server. This guide only shows an easy way to integrate Stream Chat authentication using Firebase and Flutter. - -### Flutter Firebase - -See the [Flutter Firebase getting started](https://firebase.google.com/docs/flutter/setup) docs for setup and installation instructions. - -You will also need to add the [Flutter Firebase Authentication](https://firebase.google.com/docs/auth/flutter/start), and [Flutter Firebase Cloud Functions](https://firebase.google.com/docs/functions/callable?gen=2nd#dart) packages to your app. Depending on the platform that you target, there may be specific configurations that you need to do. - -#### Starting Code - -The following code shows a basic application with **FirebaseAuth** and **FirebaseFunctions**. - -You will extend this later to execute cloud functions. - -```dart -import 'package:cloud_functions/cloud_functions.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:firebase_auth/firebase_auth.dart' as firebase_auth; -import 'package:flutter/material.dart'; -import 'dart:async'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - await Firebase.initializeApp(); - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: Scaffold( - body: Auth(), - ), - ); - } -} - -class Auth extends StatefulWidget { - const Auth({super.key}); - - @override - _AuthState createState() => _AuthState(); -} - -class _AuthState extends State { - late firebase_auth.FirebaseAuth auth; - late FirebaseFunctions functions; - - @override - void initState() { - super.initState(); - auth = firebase_auth.FirebaseAuth.instance; - functions = FirebaseFunctions.instance; - } - - final email = 'test@getstream.io'; - final password = 'password'; - - Future createAccount() async { - // Create Firebase account - await auth.createUserWithEmailAndPassword(email: email, password: password); - print('Firebase account created'); - } - - Future signIn() async { - // Sign in with Firebase - await auth.signInWithEmailAndPassword(email: email, password: password); - print('Firebase signed in'); - } - - Future signOut() async { - // Revoke Stream chat token. - final callable = functions.httpsCallable('revokeStreamUserToken'); - await callable(); - print('Stream user token revoked'); - } - - @override - Widget build(BuildContext context) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - AuthenticationState( - streamUser: auth.authStateChanges().map( - (firebaseUser) => firebaseUser != null - ? User( - id: firebaseUser.uid, - // Map other user fields here - ) - : null, - ), - ), - ElevatedButton( - onPressed: createAccount, - child: const Text('Create account'), - ), - ElevatedButton( - onPressed: signIn, - child: const Text('Sign in'), - ), - ElevatedButton( - onPressed: signOut, - child: const Text('Sign out'), - ), - ], - ), - ); - } -} - -class AuthenticationState extends StatelessWidget { - const AuthenticationState({ - super.key, - required this.streamUser, - }); - - final Stream streamUser; - - @override - Widget build(BuildContext context) { - return StreamBuilder( - stream: streamUser, - builder: (context, snapshot) { - if (snapshot.hasData) { - return (snapshot.data != null) - ? const Text('Authenticated') - : const Text('Not Authenticated'); - } - return const Text('Not Authenticated'); - }, - ); - } -} - -``` - -Running the above will give this: - -![](../assets/authentication_demo_app.jpg) - -The `Auth` widget handles all of the authentication logic. It initializes a `FirebaseAuth.instance` and uses that -in the `createAccount`, `signIn` and `signOut` methods. There is a button to invoke each of these methods. - -The `FirebaseFunctions.instance` will be used later in this guide. - -The `AuthenticationState`` widget listens to `auth.authStateChanges()` (mapped to Stream's `User`) -to display a message indicating if a user is authenticated. - -### Firebase Cloud Functions - -Firebase Cloud Functions allows you to extend Firebase with custom operations that an event can trigger: -- **Internal event**: For example, when creating a new Firebase account this is automatically triggered. -- **External event**: For example, directly calling a cloud function from your Flutter application. - -To set up your local environment to deploy cloud functions, please see the -[Cloud Functions getting started](https://firebase.google.com/docs/flutter/setup) docs. - -After initializing your project with cloud functions, you should have a **functions** folder in your project, including a `package.json` file. - -There should be two dependencies already added, **firebase-admin** and **firebase-functions**. You will also need to add the **stream-chat** dependency. - -Navigate to the **functions** folder and run `npm install stream-chat --save-prod`. - -This will install the node module and add it as a dependency to `package.json`. - -Now open `index.js` and add the following (this is the complete example): - -```js -const StreamChat = require('stream-chat').StreamChat; -const functions = require("firebase-functions"); -const admin = require("firebase-admin"); - -admin.initializeApp(); - -const serverClient = StreamChat.getInstance(functions.config().stream.key, functions.config().stream.secret); - - -// When a user is deleted from Firebase their associated Stream account is also deleted. -exports.deleteStreamUser = functions.auth.user().onDelete((user, context) => { - return serverClient.deleteUser(user.uid); -}); - -// Create a Stream user and return auth token. -exports.createStreamUserAndGetToken = functions.https.onCall(async (data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - // Create user using the serverClient. - await serverClient.upsertUser({ - id: context.auth.uid, - name: context.auth.token.name, - email: context.auth.token.email, - image: context.auth.token.image, - }); - - /// Create and return user auth token. - return serverClient.createToken(context.auth.uid); - } catch (err) { - console.error(`Unable to create user with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not create Stream user"); - } - } -}); - -// Get Stream user token. -exports.getStreamUserToken = functions.https.onCall((data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - return serverClient.createToken(context.auth.uid); - } catch (err) { - console.error(`Unable to get user token with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not get Stream user"); - } - } -}); - -// Revoke the authenticated user's Stream chat token. -exports.revokeStreamUserToken = functions.https.onCall((data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - return serverClient.revokeUserToken(context.auth.uid); - } catch (err) { - console.error(`Unable to revoke user token with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not get Stream user"); - } - } -}); - -``` - -First, you import the necessary packages and call `admin.initializeApp();` to set up Firebase cloud functions. - -Next, you initialize the **StreamChat** server client by calling `StreamChat.getInstance`. This function requires your Stream app's -**token** and **secret**. You can get this from the Stream Dashboard for your app. - -Set these values as environment data on Firebase Functions. - -```bash - firebase functions:config:set stream.key="app-key" stream.secret="app-secret" -``` - -*Replace **app-key** and **app-secret** with the values for your Stream app.* - -This creates an object of **stream** with properties **key** and **secret**. To access this environment -data use `functions.config().stream.key` and `functions.config().stream.secret`. - -See the [Firebase environment configuration](https://firebase.google.com/docs/functions/config-env) -documentation for additional information. - -To deploy these functions to Firebase, run: - -```bash -firebase deploy --only functions -``` - -### Create a Stream User and Get the User's Token - -In the `createStreamUserAndGetToken` cloud function you create an `onCall` HTTPS handler, which exposes -a cloud function that can be invoked from your Flutter app. - -```js -// Create a Stream user and return auth token. -exports.createStreamUserAndGetToken = functions.https.onCall(async (data, context) => { - // Checking that the user is authenticated. - if (!context.auth) { - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + - 'while authenticated.'); - } else { - try { - // Create user using the serverClient. - await serverClient.upsertUser({ - id: context.auth.uid, - name: context.auth.token.name, - email: context.auth.token.email, - image: context.auth.token.image, - }); - - /// Create and return user auth token. - return serverClient.createToken(context.auth.uid); - } catch (err) { - console.error(`Unable to create user with ID ${context.auth.uid} on Stream. Error ${err}`); - // Throwing an HttpsError so that the client gets the error details. - throw new functions.https.HttpsError('aborted', "Could not create Stream user"); - } - } -}); -``` - -This function first does a check to see that the client that calls it is authenticated, -by ensuring that `context.auth` is not null. If it is null, then it throws an `HttpsError` with a descriptive -message. This error can be caught in your Flutter application. - -If the caller is authenticated the function proceeds to use the `serverClient` to create a new Stream Chat -user by calling the `upsertUser` method and passing in some user data. It uses the authenticated caller's **`uid`** as an **id**. - -After the user is created it generates a token for that user. This token is then returned to the caller. - -To call this from Flutter, you will need to use the `cloud_functions` package. - -Update the **`createAccount`** method in your Flutter code to the following: - -```dart -Future createAccount() async { - // Create Firebase account - await auth.createUserWithEmailAndPassword(email: email, password: password); - print('Firebase account created'); - - // Create Stream user and get token - final callable = functions.httpsCallable('createStreamUserAndGetToken'); - final results = await callable(); - print('Stream account created, token: ${results.data}'); -} -``` - -Calling this method will do the following: -1. Create a new Firebase User and authenticate that user. -2. Call the `createStreamUserAndGetToken` cloud function and get the Stream user token for the authenticated user. - -As you can see, calling a cloud function is easy and will also send all the necessary user authentication information (such as the UID) -in the request. - -Once you have the Stream user token, you can authenticate your Stream Chat user as you normally would. - -Please see our [initialization documentation](https://getstream.io/chat/docs/flutter-dart/init_and_users/?language=dart) for more information. - -As you can see below, the User ID matches on both Firebase's and Stream's user database. - -##### Firebase Authentication Database - -![Firebase Auth Database with new user created](../assets/firebase_authentication_dashboard.jpg) - -##### Stream Chat User Database - -![Stream chat user database new account created](../assets/stream_chat_user_database.jpg) - - -### Get the Stream User Token - -The `getStreamUserToken` cloud function is very similar to the `createStreamUserAndGetToken` function. The only difference is -that it only creates a user token and does not create a new user account on Stream. - -Update the **`signIn`** method in your Flutter code to the following: - -```dart -Future signIn() async { - // Sign in with Firebase - await auth.signInWithEmailAndPassword(email: email, password: password); - print('Firebase signed in'); - - // Get Stream user token - final callable = functions.httpsCallable('getStreamUserToken'); - final results = await callable(); - print('Stream user token retrieved: ${results.data}'); -} -``` - -Calling this method will do the following: -1. Sign in using Firebase Auth. -2. Call the `getStreamUserToken` cloud function to get a Stream user token. - -:::note -The user needs to be authenticated to call this cloud function. Otherwise, the function will throw -the **failed-precondition** error that you specified. -::: - -### Revoke Stream User Token - -You may also want to revoke the Stream user token if you sign out from Firebase. - -Update the `signOut` method in your Flutter code to the following: - -```dart -Future signOut() async { - // Revoke Stream user token. - final callable = functions.httpsCallable('revokeStreamUserToken'); - await callable(); - print('Stream user token revoked'); - - // Sign out Firebase. - await auth.signOut(); - print('Firebase signed out'); -} -``` -:::note -Call the cloud function before signing out from Firebase. -::: - -### Delete Stream User - -When deleting a Firebase user account, it would make sense also to delete the -associated Stream user account. - -The cloud function looks like this: - -```js -// When a user is deleted from Firebase their associated Stream account is also deleted. -exports.deleteStreamUser = functions.auth.user().onDelete((user, context) => { - return serverClient.deleteUser(user.uid); -}); -``` - -In this function, you are listening to delete events on Firebase auth. When an account is deleted, this function will be triggered, and you can get the -user's **`uid`** and call the `deleteUser` method on the `serverClient`. - -This is not an external cloud function; it can only be triggered when an -account is deleted. - -### Conclusion - -In this guide, you have seen how to securely create Stream Chat tokens using -Firebase Authentication and Cloud Functions. - -The principles shown in this guide can be applied to your preferred authentication -provider and cloud architecture of choice. \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/04-adding_localization.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/04-adding_localization.mdx deleted file mode 100644 index 4f9456930e..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/04-adding_localization.mdx +++ /dev/null @@ -1,203 +0,0 @@ ---- -id: adding_localization -title: Localization ---- - -Adding Localization (l10n) / Internationalization (i18n) To UI Widgets - -### Introduction - -We have a dedicated package for adding localization to our UI widgets. It's called `stream_chat_localizations` and you can find it [here](https://pub.dev/packages/stream_chat_localizations). - -![](../assets/localization_support.jpg) - -## What is Localization? - -If you deploy your app to users who speak another language, you'll need to internationalize (localize) it. That means you need to write the app in a way that makes it possible to localize values like text and layouts for each language or locale that the app supports. For more information, see the [Flutter documentation](https://flutter.dev/docs/development/accessibility-and-localization/internationalization). - -What this package allows you to do is to provide localized strings for the Stream chat widgets. For example, depending on the application locale, the Stream Chat widgets will display the appropriate language. The locale will be set automatically, based on system preferences, or you could set it programmatically in your app. The package supports several different languages, with more to be added. The package allows you to override any supported language or add a new language that isn't supported. - -:::note -If you want to translate messages, or enable automatic translation, please see the [Translation documentation](https://getstream.io/chat/docs/flutter-dart/translation/?language=dart). -::: - -### Supported languages - -At the moment we support the following languages: -- [English](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart) -- [Hindi](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart) -- [Italian](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart) -- [French](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart) -- [Spanish](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart) -- [Japanese](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart) -- [Korean](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart) -- [Portuguese](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_pt.dart) -- [German](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_de.dart) -- [Norwegian](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_no.dart) -More languages will be added in the future. Feel free to [contribute](https://github.com/GetStream/stream-chat-flutter/blob/master/CONTRIBUTING.md) to add more languages. - -### Add dependency - -Add this to your package's `pubspec.yaml` file, use the latest version [![Pub](https://img.shields.io/pub/v/stream_chat_localizations.svg)](https://pub.dartlang.org/packages/stream_chat_localizations) -```yaml -dependencies: - stream_chat_localizations: ^latest_version -``` - -Then run `flutter packages get` - -### Usage - -Generally, Flutter and the Stream Chat SDK will use the system locale of the user's device, if that locale is supported (see below). If the locale is not supported we will default to `en` (however it's always possible to [customize that](#changing-the-default-language)). -Make sure to read more about localization in the [official Flutter docs](https://flutter.dev/docs/development/accessibility-and-localization/internationalization). - -```dart -import 'package:flutter/material.dart'; -import 'package:stream_chat_localizations/stream_chat_localizations.dart'; - -void main() { - WidgetsFlutterBinding.ensureInitialized(); - runApp(MyApp()); -} - -class MyApp extends StatelessWidget { - - // Setup client and channel code here - ... - - @override - Widget build(BuildContext context) { - return MaterialApp( - // Add all the supported locales - supportedLocales: const [ - Locale('en'), - Locale('hi'), - Locale('fr'), - Locale('it'), - Locale('es'), - Locale('ja'), - Locale('ko'), - Locale('pt'), - Locale('de'), - Locale('no'), - ], - // Add GlobalStreamChatLocalizations.delegates - localizationsDelegates: GlobalStreamChatLocalizations.delegates, - builder: (context, widget) => StreamChat( - client: client, - child: widget, - ), - home: StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ); - } -} -``` - -## Setting a language -The application language can be changed through system preferences or programmatically. - -### System Preferences -The application locale can be changed by changing the language for your device or emulator within the device's system preferences. - -[iOS change language](https://support.apple.com/en-us/HT204031) - -[Android change language](https://support.google.com/websearch/answer/3333234?co=GENIE.Platform%3DAndroid&hl=en) - -Note that the language needs to be supported in your application to work. - -### Programmatically -You can also set the locale programmatically in your Flutter application without changing the device's language. - -```dart -return MaterialApp( - ... - locale: const Locale('fr'), - ... -); -``` - -There are many ways that this can be set for additional control. For information and examples, see this [Stack Overflow post](https://stackoverflow.com/questions/49441212/flutter-multi-lingual-application-how-to-override-the-locale). - -### Adding a new language - -To add a new language, create a new class extending `GlobalStreamChatLocalizations` and create a delegate for it, adding it to the `delegates` array. - -Check out [this example](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/example/lib/add_new_lang.dart) to see how to add a new language. - -### Override existing languages - -To override an existing language, create a new class extending that particular language class and create a delegate for it, adding it to the `delegates` array. - -Check out [this example](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/example/lib/override_lang.dart) to see how to override an existing language. - -### Changing the default language - -To change the default language you can use the `MaterialApp.localeListResolutionCallback` property. -Here is an example of how that would look like: - -```dart - MaterialApp( - theme: ThemeData.light(), - darkTheme: ThemeData.dark(), - // Add all the supported locales - supportedLocales: const [ - Locale('en'), - Locale('hi'), - Locale('fr'), - Locale('it'), - Locale('es'), - Locale('ja'), - Locale('ko'), - ], - // locales are the locales of the device - // supportedLocales are the app supported locales - localeListResolutionCallback: (locales, supportedLocales) { - // We map the supported locales to language codes - // note that this is completely optional and this logic can be changed as you like - final supportedLanguageCodes = - supportedLocales.map((e) => e.languageCode); - if (locales != null) { - // we iterate over the locales and find the first one that is supported - for (final locale in locales) { - if (supportedLanguageCodes.contains(locale.languageCode)) { - return locale; - } - } - } - - // if we didn't find a supported language, we return the Italian language - return const Locale('it'); - }, - // Add GlobalStreamChatLocalizations.delegates - localizationsDelegates: GlobalStreamChatLocalizations.delegates, - ... - -``` - -In this case, we're using Italian as the default language. - -### ⚠️ Note on **iOS** - -For translation to work on **iOS** you need to add supported locales to -`ios/Runner/Info.plist` as described [here](https://flutter.dev/docs/development/accessibility-and-localization/internationalization#specifying-supportedlocales). - -Example: - -```xml -CFBundleLocalizations - - en - hi - fr - it - es - ja - ko - pt - de - no - -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/05-push-notifications/_category_.json b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/05-push-notifications/_category_.json deleted file mode 100644 index 26b1d64ec7..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/05-push-notifications/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Push Notifications" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/05-push-notifications/adding_push_notifications.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/05-push-notifications/adding_push_notifications.mdx deleted file mode 100644 index 6859251ed3..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/05-push-notifications/adding_push_notifications.mdx +++ /dev/null @@ -1,262 +0,0 @@ ---- -id: adding_push_notifications -title: Legacy ---- - -Adding Push Notifications To Your Application - -:::note -Version 1 (legacy) of push notifications won't be removed immediately but there won't be any new features. That's why new applications are highly recommended to use version 2 from the beginning to leverage upcoming new features. -::: - -### Introduction - -Push notifications are a core part of the experience for a messaging app. Users often need to be notified -of new messages and old notifications sometimes need to be updated silently as well. - -This guide details how to add push notifications to your app. - -Make sure to check [this section](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart) of the docs to read about the push delivery logic. - -### Setup FCM - -To integrate push notifications in your Flutter app you need to use the package [`firebase_messaging`](https://pub.dev/packages/firebase_messaging). - - -Follow the [Firebase documentation](https://firebase.flutter.dev/docs/messaging/overview/) to know how to set up the plugin for both Android and iOS. - - -Once that's done FCM should be able to send push notifications to your devices. - -### Integration with Stream - -#### Step 1 - -From the [Firebase Console](https://console.firebase.google.com/), select the project your app belongs to. - -#### Step 2 - -Click on the gear icon next to `Project Overview` and navigate to **Project settings** - -![](../../assets/firebase_project_settings.jpeg) - -#### Step 3 - -Navigate to the `Cloud Messaging` tab - -#### Step 4 - -Under `Project Credentials`, locate the `Server key` and copy it - -![](../../assets/server_key.png) - -#### Step 5 - -Upload the `Server Key` in your chat dashboard - -![](../../assets/dashboard_firebase_enable.jpeg) - -![](../../assets/dashboard_firebase_key.jpeg) - - -:::note -We are setting up the Android section, but this will work for both Android and iOS if you're using Firebase for both of them. -::: - -#### Step 6 - -Save your push notification settings changes - -![](../../assets/dashboard_save_changes.jpeg) - -**OR** - -Upload the `Server Key` via API call using a backend SDK - -```js -await client.updateAppSettings({ - firebase_config: { - server_key: 'server_key', - notification_template: `{"message":{"notification":{"title":"New messages","body":"You have {{ unread_count }} new message(s) from {{ sender.name }}"},"android":{"ttl":"86400s","notification":{"click_action":"OPEN_ACTIVITY_1"}}}}`, - data_template: `{"sender":"{{ sender.id }}","channel":{"type": "{{ channel.type }}","id":"{{ channel.id }}"},"message":"{{ message.id }}"}` - }, -}); -``` - -### Registering a device at Stream Backend - -Once you configure Firebase server key and set it up on Stream dashboard a device that is supposed to receive push notifications needs to be registered at Stream backend. This is usually done by listening for Firebase device token updates and passing them to the backend as follows: - -```dart -firebaseMessaging.onTokenRefresh.listen((token) { - client.addDevice(token, PushProvider.firebase); -}); -``` - -### Possible issues - - -We only send push notifications when the user doesn't have any active web socket connection (which is established when you call `client.connectUser`). If you set the [onBackgroundEventReceived](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/onBackgroundEventReceived.html) property of the StreamChat widget, when your app goes to background, your device will keep the WS connection alive for 1 minute, and so within this period, you won't receive any push notification. - -Make sure to read the [general push docs](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart) in order to avoid known gotchas that may make your relationship with notifications go bad 😢 - -### Testing if Push Notifications are Setup Correctly - -If you're not sure if you've set up push notifications correctly (for example you don't always receive them, they work unreliably), you can follow these steps to make sure your configuration is correct and working: - -1. Clone our repository for push testing git clone git@github.com:GetStream/chat-push-test.git - -2. `cd flutter` - -3. In folder run `flutter pub get` - -4. Input your API key and secret in `lib/main.dart` - -5. Change the bundle identifier/application ID and development team/user so you can run the app in your device (**do not** run on iOS simulator, Android emulator is fine) - -6. Add your `google-services.json/GoogleService-Info.plist` - -7. Run the app - -8. Accept push notification permission (iOS only) - -9. Tap on `Device ID` and copy it - -10. Send the app to background - -11. After configuring [stream-cli](https://github.com/GetStream/stream-cli) paste the following command on command line using your user ID - -```shell -stream chat:push:test -u -``` - -You should get a test push notification - -### App in the background but still connected - -The [StreamChat](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat-class.html) widget lets you define a [onBackgroundEventReceived](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/onBackgroundEventReceived.html) handler in order to handle events while the app is in the background, but the client is still connected. - -This is useful because it lets you keep the connection alive in cases in which the app goes in the background just for some seconds (for example multitasking, picking pictures from the gallery...) - -You can even customize the [backgroundKeepAlive](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/backgroundKeepAlive.html) duration. - -In order to show notifications in such a case we suggest using the package [`flutter_local_notifications`](https://pub.dev/packages/flutter_local_notifications); follow the package guide to successfully set up the plugin. - -Once that's done you should set the [onBackgroundEventReceived](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat/onBackgroundEventReceived.html); here is an example: - -```dart -... -StreamChat( - client: client, - onBackgroundEventReceived: (e) { - final currentUserId = client.state.user.id; - if (![ - EventType.messageNew, - EventType.notificationMessageNew, - ].contains(event.type) || - event.user.id == currentUserId) { - return; - } - if (event.message == null) return; - final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); - final initializationSettingsAndroid = - AndroidInitializationSettings('launch_background'); - final initializationSettingsIOS = IOSInitializationSettings(); - final initializationSettings = InitializationSettings( - android: initializationSettingsAndroid, - iOS: initializationSettingsIOS, - ); - await flutterLocalNotificationsPlugin.initialize(initializationSettings); - await flutterLocalNotificationsPlugin.show( - event.message.id.hashCode, - event.message.user.name, - event.message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'message channel', - 'Message channel', - 'Channel used for showing messages', - priority: Priority.high, - importance: Importance.high, - ), - iOS: IOSNotificationDetails(), - ), - ); - }, - child: .... -); -... -``` - -As you can see we generate a local notification whenever a message.new or notification.message_new event is received. - -### Foreground notifications - -Sometimes you may want to show a notification when the app is in the foreground. -For example, when you're in a channel and you receive a new message from someone in another channel. - -For this scenario, you can also use the `flutter_local_notifications` package to show a notification. - -You need to listen for new events using `StreamChatClient.on` and handle them accordingly. - -Here we're checking if the event is a `message.new` or `notification.message_new` event, and if the message is from a different user than the current user. In that case we'll show a notification. - -```dart -client.on( - EventType.messageNew, - EventType.notificationMessageNew, -).listen((event) { - if (event.message?.user?.id == client.state.currentUser?.id) { - return; - } - showLocalNotification(event, client.state.currentUser!.id, context); -}); -``` - -:::note -You should also check that the channel of the message is different than the channel in the foreground. -How you do this depends on your app infrastructure and how you handle navigation. -Take a look at the [Stream Chat v1 sample app](https://github.com/GetStream/flutter-samples/blob/main/packages/stream_chat_v1/lib/home_page.dart#L11) to see how we're doing it over there. -::: - -### Saving notification messages to the offline storage - -You may want to save received messages when you receive them via a notification so that later on when you open the app they're already there. - -To do this we need to update the push notification data payload at Stream Dashboard and clear the notification one: - -```json -{ - "message_id": "{{ message.id }}", - "channel_id": "{{ channel.id }}", - "channel_type": "{{ channel.type }}" -} -``` - -Then we need to integrate the package [`stream_chat_persistence`](https://pub.dev/packages/stream_chat_persistence) in our app that exports a persistence client, learn [here](https://pub.dev/packages/stream_chat_persistence#usage) how to set it up. - -Then during the call `firebaseMessaging.configure(...)` we need to set the `onBackgroundMessage` parameter using a TOP-LEVEL or STATIC function to handle background messages; here is an example: - -```dart -Future myBackgroundMessageHandler(message) async { - if (message.containsKey('data')) { - final data = message['data']; - final messageId = data['message_id']; - final channelId = data['channel_id']; - final channelType = data['channel_type']; - final cid = '$channelType:$channelId'; - - final client = StreamChatClient(apiKey); - final persistenceClient = StreamChatPersistenceClient(); - await persistenceClient.connect(userId); - - final message = await client.getMessage(messageId).then((res) => res.message); - - await persistenceClient.updateMessages(cid, [message]); - persistenceClient.disconnect(); - - /// This can be done using the package flutter_local_notifications as we did before 👆 - _showLocalNotification(); - } -} -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/05-push-notifications/adding_push_notifications_v2.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/05-push-notifications/adding_push_notifications_v2.mdx deleted file mode 100644 index 81ee284ad5..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/05-push-notifications/adding_push_notifications_v2.mdx +++ /dev/null @@ -1,355 +0,0 @@ ---- -id: adding_push_notifications_v2 -title: Push Notifications ---- - -Adding Push Notifications (V2) To Your Application - -### Introduction - -This guide details how to add push notifications to your app. - -Push notifications are a core part of the experience for a messaging app. Users often need to be notified -of new messages and old notifications sometimes need to be updated silently. - -Stream Chat sends push notification to channel members that have at least one registered device. -Push notifications are only sent for new messages and not for other events. -You can use [Webhooks](https://getstream.io/chat/docs/android/webhooks_overview/) to send push notifications on other types of events. - -You can read more about Stream’s [push delivery logic](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart#push-delivery-rules). - -To receive push notifications from Stream Chat, 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). - -### Push Delivery Rules - -Push message delivery behaves according to these rules: - -- Push notifications are sent only for new messages. -- Only channel members receive push messages. -- Members receive push notifications regardless of their online status. -- Replies inside a [thread](https://getstream.io/chat/docs/threads/) are only sent to users that are part of that thread: - - They posted at least one message - - They were mentioned -- Messages from muted users are not sent. -- Messages from muted channels are not sent. -- Messages are sent to all registered devices for a user (up to 25). -- The message doesn't contain the flag `skip_push` as true. -- `push_notifications` is enabled (default) on the channel type for message is sent. - -:::caution - -Push notifications require membership. Watching a channel isn't enough. - -::: - -### Setup FCM - -To integrate push notifications in your Flutter app, you need to use the package [`firebase_messaging`](https://pub.dev/packages/firebase_messaging). - -Follow the [Flutter Firebase documentation](https://firebase.flutter.dev/docs/messaging/overview/) to set up the plugin for Android and iOS. -Additional setup and instructions can be found [here](https://firebase.google.com/docs/cloud-messaging/flutter/client). Be sure to read this documentation to understand Firebase messaging functionality. - -Once that's done, FCM should be able to send push notifications to your devices. - -### Integration With Stream - -#### Step 1 - Get the Firebase Credentials - -These credentials are the [private key file](https://firebase.google.com/docs/admin/setup#:~:text=To%20generate%20a%20private%20key%20file%20for%20your%20service%20account%3A) 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 can upload your Firebase credentials using either the dashboard or the app settings API (available only in backend SDKs). - -##### Using the Stream Dashboard - -1. Go to the **Chat Overview** page on Stream Dashboard. - -![](../../assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png) - -2. Enable **Firebase Notification** toggle on **Chat Overview**. - -![](../../assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png) - -3. Enter your Firebase Credentials and press `"Save"`. - -##### Using the API - -You can also enable Firebase notifications and upload the Firebase credentials using one of our server SDKs. - -For example, using the Stream JavaScript SDK: - -```js -const client = StreamChat.getInstance('api_key', 'api_secret'); -client.updateAppSettings({ - push_config: { - version: 'v2' - }, - firebase_config: { - credentials_json: fs.readFileSync( - './firebase-credentials.json', - 'utf-8', - ), - }); -``` - -### Registering a Device With Stream Backend - -Once you configure a Firebase server key 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. This is usually done by listening for Firebase device token updates and passing them to the backend as follows: - -```dart -firebaseMessaging.onTokenRefresh.listen((token) { - client.addDevice(token, PushProvider.firebase); -}); -``` - -Push Notifications v2 also supports specifying a name for the push device tokens you register. By setting the optional `pushProviderName` parameter in the `addDevice` call, you can support different configurations between the device and the `PushProvider`. - -```dart -firebaseMessaging.onTokenRefresh.listen((token) { - client.addDevice(token, PushProvider.firebase, pushProviderName: 'my-custom-config'); -}); -``` - -### Receiving Notifications - -Push notifications behave differently depending on whether you are using iOS or Android. -See [here](https://firebase.flutter.dev/docs/messaging/usage#message-types) to understand the difference between **notification** and **data** payloads. - -#### iOS - -On iOS, we send both a **notification** and a **data** payload. -This means you don't need to do anything special to get the notification to show up. However, you might want to handle the data payload to perform some logic when the user taps on the notification. - -To update the template, you can use a backend SDK. -For example, using the Stream JavaScript SDK: - -```js -const client = StreamChat.getInstance(‘api_key’, ‘api_secret’); -const apn_template = `{ - "aps": { - "alert": { - "title": "New message from {{ sender.name }}", - "body": "{{ truncate message.text 2000 }}" - }, - "mutable-content": 1, - "category": "stream.chat" - }, - "stream": { - "sender": "stream.chat", - "type": "message.new", - "version": "v2", - "id": "{{ message.id }}", - "cid": "{{ channel.cid }}" - } -}`; - -client.updateAppSettings({ - firebase_config: { - apn_template, - }); -``` - -#### Android - -On Android, we send only a **data** payload. This gives you more flexibility and lets you decide what to do with the notification. - -For example, you can listen and generate a notification from them. - -The code below demonstrates how to generate a notification when a **data-only** message is received and the app is in the background. - -There are a few things to keep in mind about your background message handler: - -1. It must not be an anonymous function. -2. It must be a top-level function (not a class method which requires initialization). -3. It must be annotated with @pragma('vm:entry-point') right above the function declaration (otherwise it may be removed during tree shaking for release mode). - -For additional information on background messages, please see the [Firebase documentation](https://firebase.google.com/docs/cloud-messaging/flutter/receive#background_messages). - -```dart -@pragma('vm:entry-point') -Future onBackgroundMessage(RemoteMessage message) async { - final chatClient = StreamChatClient(apiKey); - - chatClient.connectUser( - User(id: userId), - userToken, - connectWebSocket: false, - ); - - handleNotification(message, chatClient); -} - -void handleNotification( - RemoteMessage message, - StreamChatClient chatClient, -) async { - - final data = message.data; - - if (data['type'] == 'message.new') { - final flutterLocalNotificationsPlugin = await setupLocalNotifications(); - final messageId = data['id']; - final response = await chatClient.getMessage(messageId); - - flutterLocalNotificationsPlugin.show( - 1, - 'New message from ${response.message.user!.name} in ${response.channel!.name}', - response.message.text, - const NotificationDetails( - android: AndroidNotificationDetails( - 'new_message', - 'New message notifications channel', - )), - ); - } -} - -FirebaseMessaging.onBackgroundMessage(onBackgroundMessage); -``` - -In the above example, you get the message details using the `getMessage` method, and then you use the [`flutter_local_notifications`](https://pub.dev/packages/flutter_local_notifications) package to show the actual notification. - -##### Using a Template on Android - -Adding a **notification** payload to Android notifications is still possible. -You can do so by adding a template using a backend SDK. -For example, using the Stream JavaScript SDK: - -```js -const client = StreamChat.getInstance(‘api_key’, ‘api_secret’); -const notification_template = ` -{ - "title": "{{ sender.name }} @ {{ channel.name }}", - "body": "{{ message.text }}", - "click_action": "OPEN_ACTIVITY_1", - "sound": "default" -}`; - -client.updateAppSettings({ - firebase_config: { - notification_template, - }); -``` - -### Possible Issues - -Make sure to read the [general push notification docs](https://getstream.io/chat/docs/flutter-dart/push_introduction/?language=dart) to prevent common issues with notifications 😢. - -### Testing if Push Notifications are Setup Correctly - -If you're not sure whether you've set up push notifications correctly, for example, you don't always receive them, or they don’t work reliably, then you can follow these steps to make sure your configuration is correct and working: - -1. Clone our repository for push testing: `git clone git@github.com:GetStream/chat-push-test.git` -2. `cd chat-push-test/flutter` -3. In that folder run `flutter pub get` -4. Input your API key and secret in `lib/main.dart` -5. Change the bundle identifier/application ID and development team/user so you can run the app on your physical device.**Do not** run on an iOS simulator, as it will not work. Testing on an Android emulator is fine. -6. Add your `google-services.json/GoogleService-Info.plist` -7. Run the app -8. Accept push notification permission (iOS only) -9. Tap on `Device ID` and copy it -10. After configuring [stream-cli](https://github.com/GetStream/stream-cli), run the following command using your user ID: - -```shell -stream chat:push:test -u -``` - -You should get a test push notification 🥳 - -### Foreground Notifications - -You may want to show a notification when the app is in the foreground. -For example, when you're in a channel and receive a new message from someone in another channel. - -For this scenario, you can also use the `flutter_local_notifications` package to show a notification. - -You need to listen for new events using `FirebaseMessaging.onMessage.listen()` and handle them accordingly: - -```dart -FirebaseMessaging.onMessage.listen((message) async { - handleNotification( - message, - chatClient, - ); -}); -``` - -:::note -You should also check that the message's channel differs from the channel in the foreground. -How you do this depends on your app infrastructure and how you handle navigation. - -Take a look at the [Stream Chat v1 sample app](https://github.com/GetStream/flutter-samples/blob/main/packages/stream_chat_v1/lib/home_page.dart#L11) to see how we're doing it over there. -::: - -### Saving Notification Messages to the Offline Storage (Only Android) - -When the app is closed, you can save incoming messages when you receive them via a notification so that they're already there later when you open the app. - -To do this, you need to integrate the package [`stream_chat_persistence`](https://pub.dev/packages/stream_chat_persistence) that exports a persistence client. See [here](https://pub.dev/packages/stream_chat_persistence#usage) for information on how to set it up. - -Then calling `FirebaseMessaging.onBackgroundMessage(...)` you need to use a TOP-LEVEL or STATIC function to handle background messages. - -For additional information on background messages, please see the [Firebase documentation](https://firebase.google.com/docs/cloud-messaging/flutter/receive#background_messages). - -Here is an example: - -```dart -@pragma('vm:entry-point') -Future onBackgroundMessage(RemoteMessage message) async { - final chatClient = StreamChatClient(apiKey); - final persistenceClient = StreamChatPersistenceClient(); - - await persistenceClient.connect(userId); - - chatClient.connectUser( - User(id: userId), - userToken, - connectWebSocket: false, - ); - - handleNotification(message, chatClient); -} - -void handleNotification( - RemoteMessage message, - StreamChatClient chatClient, -) async { - final data = message.data; - if (data['type'] == 'message.new') { - final flutterLocalNotificationsPlugin = await setupLocalNotifications(); - final messageId = data['id']; - final cid = data['cid']; - final response = await chatClient.getMessage(messageId); - await persistenceClient.updateMessages(cid, [response.message]); - - persistenceClient.disconnect(); - - flutterLocalNotificationsPlugin.show( - 1, - 'New message from ${response.message.user.name} in ${response.channel.name}', - response.message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'new_message', - 'New message notifications channel', - )), - ); - } -} - -FirebaseMessaging.onBackgroundMessage(onBackgroundMessage); -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/06-end_to_end_chat_encryption.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/06-end_to_end_chat_encryption.mdx deleted file mode 100644 index cf204cfc60..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/06-end_to_end_chat_encryption.mdx +++ /dev/null @@ -1,259 +0,0 @@ ---- -id: end_to_end_chat_encryption -title: Encryption ---- - -Adding End To End Encryption to your Chat App - -## Introduction - -When you communicate over a chat application with another person or group, -you may exchange sensitive information, like personally identifiable information, financial details, or passwords. -A chat application should use end-to-end encryption to ensure that users' data stays secure. - -:::note -Before you start, keep in mind that this guide is a basic example intended for educational purposes only. -If you want to implement end-to-end encryption in your production app, please consult a security professional first. -There’s a lot more to consider from a security perspective that isn’t covered here. -::: - -## What is End-to-End Encryption? - -End-to-end encryption (E2EE) is the process of securing a message from third parties so that only the sender and receiver can access the message. -E2EE provides security by storing the message in an encrypted form on the application's server or database. - -You can only access the message by decrypting and signing it using a known public key (distributed freely) -and a corresponding private key (only known by the owner). - -Each user in the application has their own public-private key pair. -Public keys are distributed publicly and encrypt the sender’s messages. -The receiver can only decrypt the sender’s message with the matching private key. - -Check out the diagram below for an example: - -![](../assets/end_to_end_encryption.png) - -## Setup - -### Dependencies - -Add the [`webcrypto`](https://pub.dev/packages/webcrypto) package in your `pubspec.yaml` file. - -```yaml -dependencies: - webcrypto: ^0.5.2 # latest version -``` - -### Generate Key Pair - -Write a function that generates a key pair using the **ECDH** algorithm and the **P-256** elliptic curve (**P-256** is well-supported and -offers the right balance of security and performance). - -The pair will consist of two keys: -- **PublicKey**: The key that is linked to a user to encrypt messages. -- **PrivateKey**: The key that is stored locally to decrypt messages. - -```dart -Future generateKeys() async { - final keyPair = await EcdhPrivateKey.generateKey(EllipticCurve.p256); - final publicKeyJwk = await keyPair.publicKey.exportJsonWebKey(); - final privateKeyJwk = await keyPair.privateKey.exportJsonWebKey(); - - return JsonWebKeyPair( - privateKey: json.encode(privateKeyJwk), - publicKey: json.encode(publicKeyJwk), - ); -} - -// Model class for storing keys -class JsonWebKeyPair { - const JsonWebKeyPair({ - required this.privateKey, - required this.publicKey, - }); - - final String privateKey; - final String publicKey; -} -``` - -### Generate a Cryptographic Key - -Next, create a symmetric **Cryptographic Key** using the keys generated in the previous step. -You will use those keys to encrypt and decrypt messages. - -```dart -// SendersJwk -> sender.privateKey -// ReceiverJwk -> receiver.publicKey -Future> deriveKey(String senderJwk, String receiverJwk) async { - // Sender's key - final senderPrivateKey = json.decode(senderJwk); - final senderEcdhKey = await EcdhPrivateKey.importJsonWebKey( - senderPrivateKey, - EllipticCurve.p256, - ); - - // Receiver's key - final receiverPublicKey = json.decode(receiverJwk); - final receiverEcdhKey = await EcdhPublicKey.importJsonWebKey( - receiverPublicKey, - EllipticCurve.p256, - ); - - // Generating CryptoKey - final derivedBits = await senderEcdhKey.deriveBits(256, receiverEcdhKey); - return derivedBits; -} -``` - -### Encrypting Messages - -Once you have generated the **Cryptographic Key**, you're ready to encrypt the message. -You can use the **AES-GCM** algorithm for its known security and performance balance and good browser availability. - -```dart -// The "iv" stands for initialization vector (IV). To ensure the encryption’s strength, -// each encryption process must use a random and distinct IV. -// It’s included in the message so that the decryption procedure can use it. -final Uint8List iv = Uint8List.fromList('Initialization Vector'.codeUnits); -``` - -```dart -Future encryptMessage(String message, List deriveKey) async { - // Importing cryptoKey - final aesGcmSecretKey = await AesGcmSecretKey.importRawKey(deriveKey); - - // Converting message into bytes - final messageBytes = Uint8List.fromList(message.codeUnits); - - // Encrypting the message - final encryptedMessageBytes = - await aesGcmSecretKey.encryptBytes(messageBytes, iv); - - // Converting encrypted message into String - final encryptedMessage = String.fromCharCodes(encryptedMessageBytes); - return encryptedMessage; -} -``` - -### Decrypting Messages - -Decrypting a message is the opposite of encrypting one. -To decrypt a message to a human-readable format, use the code snippet below: - -```dart -Future decryptMessage(String encryptedMessage, List deriveKey) async { - // Importing cryptoKey - final aesGcmSecretKey = await AesGcmSecretKey.importRawKey(deriveKey); - - // Converting message into bytes - final messageBytes = Uint8List.fromList(encryptedMessage.codeUnits); - - // Decrypting the message - final decryptedMessageBytes = - await aesGcmSecretKey.decryptBytes(messageBytes, iv); - - // Converting decrypted message into String - final decryptedMessage = String.fromCharCodes(decryptedMessageBytes); - return decryptedMessage; -} -``` - -## Implement as a Stream Chat Feature - -Now that your setup is complete you can use it to implement end-to-end encryption in your app. - -### Store User's Public Key - -The first thing you need to do is store the generated `publicKey` as an `extraData` property, in order -for other users to encrypt messages. - -```dart -// Generating keyPair using the function defined in above steps -final keyPair = generateKeys(); -``` - -```dart -await client.connectUser( - User( - id: 'cool-shadow-7', - name: 'Cool Shadow', - image: 'https://getstream.io/cool-shadow', - - // set publicKey as a extraData property - extraData: { 'publicKey': keyPair.publicKey }, - ), - client.devToken('cool-shadow-7').rawValue, -); -``` - -### Sending Encrypted Messages - -Now you will use the `encryptMessage()` function created in the previous steps to encrypt the message. - -To do that, you need to make some minor changes to the **StreamMessageInput** widget. - -```dart -final receiverJwk = receiver.extraData['publicKey']; - -// Generating derivedKey using user's privateKey and receiver's publicKey -final derivedKey = await deriveKey(keyPair.privateKey, receiverJwk); -``` - -```dart -StreamMessageInput( - - ... - - preMessageSending: (message) async { - // Encrypting the message text using derivedKey - final encryptedMessage = await encryptMessage(message.text, derivedKey); - - // Creating a new message with the encrypted message text - final newMessage = message.copyWith(text: encryptedMessage); - - return newMessage; - }, -), -``` - -`preMessageSending` is a parameter that allows your app to process the message before it goes to Stream’s server. -Here, you have used it to encrypt the message before sending it to Stream’s backend. - -### Showing Decrypted Messages - -Now, it’s time to decrypt the message and present it in a human-readable format to the receiver. - -You can customize the **StreamMessageListView** widget to have a custom `messagebuilder`, that can decrypt the message. - -```dart -StreamMessageListView( - ... - messageBuilder: (context, messageDetails, currentMessages, defaultWidget) { - // Retrieving the message from details - final message = messageDetails.message; - - // Decrypting the message text using the derivedKey - final decryptedMessageFuture = decryptMessage(message.text, derivedKey); - return FutureBuilder( - future: decryptedMessageFuture, - builder: (context, snapshot) { - if (snapshot.hasError) return Text('Error: ${snapshot.error}'); - if (!snapshot.hasData) return Container(); - - // Updating the original message with the decrypted text - final decryptedMessage = message.copyWith(text: snapshot.data); - - // Returning defaultWidget with updated message - return defaultWidget.copyWith( - message: decryptedMessage, - ); - }, - ); - }, -), -``` - -That's it. That's all you need to implement E2EE in a Stream powered chat app. - -For more details, check out our [end-to-end encrypted chat article](https://getstream.io/blog/end-to-end-encrypted-chat-in-flutter/#whats-end-to-end-encryption). diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/07-error_reporting_with_sentry.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/07-error_reporting_with_sentry.mdx deleted file mode 100644 index dbbe312e80..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/07-error_reporting_with_sentry.mdx +++ /dev/null @@ -1,143 +0,0 @@ ---- -id: error_reporting_with_sentry -title: Error Reporting ---- - -Error Reporting With Sentry - -## Introduction - -While one always tries to create apps that are free of bugs, they're sure to crop up from time to time. Since buggy apps lead to unhappy users and customers, it's important to understand how often your users experience bugs and where those bugs occur. That way, you can prioritize the bugs with the highest impact and work to fix them. - -Whenever an error occurs, create a report containing the error that occurred and the associated stack trace. You can then send the report to an error tracking service, such as [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), or [Firebase Crashlytics](https://firebase.google.com/docs/crashlytics). - -The error tracking service aggregates all of the crashes your users experience and groups them together. This allows you to know how often your app fails and where your users run into trouble. - -In this guide, learn how to report Stream Chat errors to the [Sentry](https://sentry.io/welcome/) crash reporting service using the following steps. - -### 1. Get a DSN From Sentry - -Before reporting errors to Sentry, you need a “DSN” to uniquely identify your app with the Sentry service: -To get a DSN, use the following steps: - -- [Create an account with Sentry](https://sentry.io/signup/). -- Log in to the account. -- Create a new Flutter project. -- Copy the code snippet that includes the DSN. - -### 2. Import the Sentry package - -Import the `sentry_flutter` package into your app. The sentry package makes it easier to send error reports to the Sentry error tracking service. - -```yaml -dependencies: - sentry_flutter: -``` - -### 3. Initialize the Sentry SDK - -Initialize the SDK to capture different unhandled errors automatically. - -```dart -import 'package:sentry_flutter/sentry_flutter.dart'; - -Future main() async { - await SentryFlutter.init( - (options) => options.dsn = 'https://example@sentry.io/example', - appRunner: () => runApp(const MyApp()), - ); -} -``` - -Or, if you want to run your app in your own error zone, use `runZonedGuarded`: - -```dart -void main() async { - /// Captures errors reported by the Flutter framework. - FlutterError.onError = (FlutterErrorDetails details) { - if (kDebugMode) { - // In development mode, simply print to console. - FlutterError.dumpErrorToConsole(details); - } else { - // In production mode, report to the application zone to report to Sentry. - Zone.current.handleUncaughtError(details.exception, details.stack!); - } - }; - - Future _reportError(dynamic error, StackTrace stackTrace) async { - // Print the exception to the console. - if (kDebugMode) { - // Print the full stack trace in debug mode. - print(stackTrace); - return; - } else { - // Send the Exception and Stacktrace to sentry in Production mode. - await Sentry.captureException(error, stackTrace: stackTrace); - } - } - - runZonedGuarded( - () async { - await SentryFlutter.init( - (options) => options.dsn = 'https://example@sentry.io/example', - ); - runApp(const MyApp()); - }, - _reportError, - ); -} -``` - -Alternatively, you can pass the DSN to Flutter using the **dart-define** tag: - -```bash ---dart-define SENTRY_DSN=https://example@sentry.io/example -``` - -### 4. Integration With StreamChat Applications - -Override the default `logHandlerFunction` to send errors to Sentry. - -```dart -void sampleAppLogHandler(LogRecord record) async { - if (kDebugMode) StreamChatClient.defaultLogHandler(record); - - // Report errors to Sentry - if (record.error != null || record.stackTrace != null) { - await Sentry.captureException( - record.error, - stackTrace: record.stackTrace, - ); - } -} - -StreamChatClient buildStreamChatClient( - String apiKey, { - Level logLevel = Level.SEVERE, -}) { - return StreamChatClient( - apiKey, - logLevel: logLevel, - logHandlerFunction: sampleAppLogHandler, // Pass the overridden logHandlerFunction - ); -} -``` - -### 5. Capture Errors Programmatically - -Besides the automatic error reporting that Sentry generates by importing and initializing the SDK, -you can use the API to manually report errors to Sentry: - -```dart -await Sentry.captureException(exception, stackTrace: stackTrace); -``` - -For more information, see the [Sentry API](https://pub.dev/documentation/sentry_flutter/latest/sentry_flutter/sentry_flutter-library.html) docs on Pub. - -### Complete Example - -To view a working example, see the [Stream Sample app](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). - -### Learn More - -Extensive documentation about using the Sentry SDK can be found on [Sentry's site](https://docs.sentry.io/platforms/flutter/). diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-adding_chat_to_video_livestreams.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-adding_chat_to_video_livestreams.mdx deleted file mode 100644 index 72f501208d..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-adding_chat_to_video_livestreams.mdx +++ /dev/null @@ -1,97 +0,0 @@ ---- -id: adding_chat_to_video_livestreams -title: Livestreams Integration ---- - -Adding Chat To Video Livestreams - -### Introduction - -Video livestreams are usually complemented with a chat section to make the livestream more interactive -and encourage retention. There are several ways to show the chat interface on the screen and requires -some design choices. - -This guide details multiple ways of adding chat functionality to your video livestream. - -### Implementing Chat - -There are two common scenarios in live-streaming applications depending how well integrated the two -components (video + chat) are allowed to be on the screen. Two common types are split-screen and a -chat overlay that fades in. - -Let's explore creating both types: - -### Split-screen - -In the split-screen implementation, we have a visual split between the video and the message list. -This allows the content to be unobstructed by chat and have a clear separation of boundaries. - -![](../assets/live_stream_1.jpg) - -```dart -Scaffold( - body: Column( - children: [ - Expanded( - child: // Your video implementation here, - ), - Expanded( - child: Column( - children: [ - Expanded( - child: StreamMessageListView(), - ), - StreamMessageInput(), - ], - ), - ), - ], - ), -) -``` - -### Overlapping chat with a transparency gradient - -Another way to add chat is to overlay the video content with messages which progressively fade out -as we go to the top of the screen. This gives the content a more rich feel as it takes the whole -screen and allows the chat to be more homogeneously integrated with the content. - -The second type looks like this: - -![](../assets/live_stream_2.jpg) - -We can use a `Stack` for achieving this: - -```dart -Stack( - children: [ - // Add your video implementation here - ShaderMask( - shaderCallback: (rect) { - return const LinearGradient( - begin: Alignment.bottomCenter, - end: Alignment.topCenter, - colors: [Colors.black, Colors.transparent], - stops: [0.4, 0.8]).createShader( - Rect.fromLTRB(0, 0, rect.width, rect.height), - ); - }, - blendMode: BlendMode.dstIn, - child: Column( - children: const [ - Expanded( - child: StreamMessageListViewTheme( - data: StreamMessageListViewThemeData( - backgroundColor: Colors.transparent, - ), - child: StreamMessageListView(), - ), - ), - StreamMessageInput(), - ], - ), - ), - ], -), -``` - diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-migrations/_category_.json b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-migrations/_category_.json deleted file mode 100644 index e30f7ae440..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-migrations/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Migrations" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-migrations/migration_guide_4_0.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-migrations/migration_guide_4_0.mdx deleted file mode 100644 index f2c830a71b..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-migrations/migration_guide_4_0.mdx +++ /dev/null @@ -1,753 +0,0 @@ ---- -id: migration_guide_4_0 -title: v4.0 -slug: /guides/migration_guide_4_0/ ---- - -**Version 4.0.0** of the Stream Chat Flutter SDK carries significant architectural changes to improve the developer experience by giving you more control and flexibility in how you use our core components and UI widgets. - -This v4.0 Migration Guide is intended to enumerate and better explain the changes in the SDK. - -If you find any bugs or have any questions, please file an [issue on our GitHub repository](https://github.com/GetStream/stream-chat-flutter/issues). We want to support you as much as we can with this migration. - -Code examples: - -- See our [Stream Chat Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) for an up-to-date guide using the latest Stream Chat version. -- See the [Stream Flutter Samples repository](https://github.com/GetStream/flutter-samples) with our full fledged messaging [sample application](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). - -All of our documentation has also been updated to support v4, so all of the guides and examples will have updated code. - -### Dependencies - -To migrate to v4.0.0, update your `pubspec.yaml` with the correct Stream chat package you're using: - -```yaml -dependencies: - stream_chat_flutter: ^4.0.0 # full UI, core and client packages - stream_chat_flutter_core: ^4.0.0 # core and client packages - stream_chat: ^4.0.0 # client package -``` - ---- - -## Name Changes - -The majority of the Stream Chat widgets and classes have now been renamed to have a “Stream” prefix associated with them. This increases Stream widgets' discoverability and avoids name conflicts when importing. - -For example, `MessageListView` is now called `StreamMessageListView`, and `UserAvatar` is renamed to `StreamUserAvatar`. - -**The old class names are deprecated and will be removed in the next major release (v5.0.0).** - -See the sections below on “deprecated classes” for a complete list of changes. Some of these classes/widgets have undergone functional changes as well, that will be explore in the following sections. - -## Removed Functionality/Widgets - -This section highlights functionality removed. - -### Removed Methods And Classes - -In version 4 we removed the following deprecated methods and classes: - -* `Channel.banUser` - -* `Channel.unbanUser` - -* `ClientState.user` - -* `ClientState.userStream` - -* `MessageWidget.allRead` - -* `MessageWidget.readList` - -* `StreamChat.user` - -* `StreamChat.userStream` - -* `StreamChatCore.user` - -* `StreamChatCore.userStream` - -These were marked as deprecated in v3. - -### Video Compression - -The automatic video compression when uploading a video has been removed. You can integrate this yourself by manipulating attachments using a [custom attachment uploader](https://getstream.io/chat/docs/flutter-dart/file_uploads/?language=dart). - -### Slidable Channel List Item - -The default slidable channel preview behavior has been removed. We have created a [guide](../../02-stream_chat_flutter/03-custom_widgets/07-slidable_channel_list_preview.mdx) showing you how you can easily add this functionality yourself. - -![Slidable demo](../../assets/slidable_demo.jpg) - -### Pin Permission - -`pinPermissions` is no longer needed in the **MessageListView** widget. The permissions are automatically fetched for each Stream project. To enable users to pin the message, make sure the pin permissions are granted for different types of users on your [Stream application dashboard](https://dashboard.getstream.io/). - ---- - -## Deprecated Classes - -This section covers all the deprecated classes and widgets in the Stream chat packages. Some of these have also undergone functional changes, for example, **MessageInput** and **ChannelsBloc**. These are discussed in more detail below. - -The majority of the Stream widgets and classes have now been renamed to have a **"Stream"** prefix associated with them. - -Changes: - -- `AttachmentTitle` in favor of `StreamAttachmentTitle` -- `AttachmentUploadStateBuilder` in favor of `StreamAttachmentsUploadStateBuilder` -- `AttachmentWidget` in favor of `StreamAttachmentWidget` -- `AvatarThemeData` in favor of `StreamAvatarThemeData` -- `ChannelAvatar` in favor of `StreamChannelAvatar` -- `ChannelBottomSheet` in favor of `StreamChannelInfoBottomSheet` -- `ChannelHeader` in favor of `StreamChannelHeader` -- `ChannelHeaderTheme` in favor of `StreamChannelHeaderTheme` -- `ChannelHeaderThemeData` in favor of `StreamChannelHeaderThemeData` -- `ChannelInfo` in favor of `StreamChannelInfo` -- `ChannelListHeader` in favor of `StreamChannelListHeader` -- `ChannelListHeaderTheme` in favor of `StreamChannelListHeaderTheme` -- `ChannelListHeaderThemeData` in favor of `StreamChannelListHeaderThemeData` -- `ChannelListView` in favor of `StreamChannelListView` -- `ChannelListViewTheme` in favor of `StreamChannelListViewTheme` -- `ChannelListViewThemeData` in favor of `StreamChannelListViewThemeData` -- `ChannelListHeader` in favor of `StreamChannelListHeader` -- `ChannelListView` in favor of `StreamChannelListView` -- `ChannelName` in favor of `StreamChannelName` -- `ChannelPreview` in favor of `StreamChannelListTile` -- `ChannelPreviewTheme` in favor of `StreamChannelPreviewTheme` -- `ChannelPreviewThemeData` in favor of `StreamChannelPreviewThemeData` -- `ChannelName` in favor of `StreamChannelName` -- `ColorTheme` in favor of `StreamColorTheme` -- `CommandsOverlay` in favor of `StreamCommandsOverlay` -- `ConnectionStatusBuilder` in favor of `StreamConnectionStatusBuilder` -- `DateDivider` in favor of `StreamDateDivider` -- `DeletedMessage` in favor of `StreamDeletedMessage` -- `EmojiOverlay` in favor of `StreamEmojiOverlay` -- `FileAttachment` in favor of `StreamFileAttachment` -- `FullScreenMedia` in favor of `StreamFullScreenMedia` -- `GalleryFooter` in favor of `StreamGalleryFooter` -- `GalleryFooterThemeData` in favor of `StreamGalleryFooterThemeData` -- `GalleryHeader` in favor of `StreamGalleryHeader` -- `GalleryHeaderTheme` in favor of `StreamGalleryHeaderTheme` -- `GalleryHeaderThemeData` in favor of `StreamGalleryHeaderThemeData` -- `GiphyAttachment` in favor of `StreamGiphyAttachment` -- `GradientAvatar` in favor of `StreamGradientAvatar` -- `GroupAvatar` in favor of `StreamGroupAvatar` -- `ImageAttachment` in favor of `StreamImageAttachment` -- `ImageGroup` in favor of `StreamImageGroup` -- `InfoTile` in favor of `StreamInfoTile` -- `MediaListView` in favor of `StreamMediaListView` -- `MessageAction` in favor of `StreamMessageAction` -- `MessageActionsModal` in favor `StreamMessageActionsModal` -- `MessageInput` in favor of `StreamMessageInput` -- `MessageInputTheme` in favor of `StreamMessageInputTheme` -- `MessageInputThemeData` in favor of `StreamMessageInputThemeData` -- `MessageInputState` in favor of `StreamMessageInput` -- `MessageListView` in favor of `StreamMessageListView` -- `MessageListViewTheme` in favor of `StreamMessageListViewTheme` -- `MessageListViewThemeData` in favor of `StreamMessageListViewThemeData` -- `MessageSearchListView` in favor of `StreamMessageSearchListView` -- `MessageSearchListViewTheme` in favor of `StreamMessageSearchListViewTheme` -- `MessageSearchListViewThemeData` in favor of `StreamMessageSearchListViewThemeData` -- `MessageReactionsModal` in favor of `StreamMessageReactionsModal` -- `MessageSearchItem` in favor of `StreamMessageSearchItem` -- `MessageSearchListView` in favor of `StreamMessageSearchListView` -- `MessageText` in favor of `StreamMessageText` -- `MessageWidget` in favor of `StreamMessageWidget` -- `MessageThemeData` in favor of `StreamMessageThemeData` -- `MultiOverlay` in favor of `StreamMultiOverlay` -- `OptionListTile` in favor of `StreamOptionListTile` -- `QuotedMessageWidget` in favor of `StreamQuotedMessageWidget` -- `ReactionBubble` in favor of `StreamReactionBubble` -- `ReactionIcon` in favor of `StreamReactionIcon` -- `ReactionPicker` in favor of `StreamReactionPicker` -- `SendingIndicator` in favor of `StreamSendingIndicator` -- `SystemMessage` in favor of `StreamSystemMessage` -- `TextTheme` in favor of `StreamTextTheme` -- `ThreadHeader` in favor of `StreamThreadHeader` -- `TypingIndicator` in favor of `StreamTypingIndicator` -- `UnreadIndicator` in favor of `SteamUnreadIndicator` -- `UploadProgressIndicator` in favor of `StreamUploadProgressIndicator` -- `UrlAttachment` in favor of `StreamUrlAttachment` -- `UserAvatar` in favor of `StreamUserAvatar` -- `UserItem` in favor of `StreamUserItem` -- `UserListView` in favor of `StreamUserListView` -- `UserListViewTheme` in favor of `StreamUserListViewTheme` -- `UserListViewThemeData` in favor of `StreamUserListViewThemeData` -- `UserMentionTile` in favor of `StreamUserMentionTile` -- `UserMentionsOverlay` in favor of `StreamUserMentionsOverlay` -- `VideoAttachment` in favor of `StreamVideoAttachment` -- `VideoService` in favor of `StreamVideoService` -- `VideoThumbnailImage` in favor of `StreamVideoThumbnailImage` -- `VisibleFootnote` in favor of `StreamVisibleFootnote` - -## ChannelListView to StreamChannelListView - -The `ChannelListView` widget has been deprecated, and it is now recommended to use `StreamChannelListView`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `StreamChannelListController`. This controller manages the content for a channel list; it lets you perform tasks such as: - -- Load initial data. -- Use channel events handlers. -- Load more data using `loadMore`. -- Replace the previously loaded channels. -- Return/Create a new channel and start watching it. -- Pause and Resume all subscriptions added to this composite. - -For more information see the [`StreamChannelListView` documentation](../../02-stream_chat_flutter/04-channel_list/stream_channel_list_view.mdx). - -### ChannelsBloc to StreamChannelListController - -The `ChannelsBloc` widget should be replaced with `StreamChannelListController`. This controller provides all the functionality needed to query and manipulate channel data previously accessible through `ChannelsBloc`. - -For more information see the [`StreamChannelListController` documentation](../../04-stream_chat_flutter_core/stream_channel_list_controller.mdx). - -### StreamChannelListView Examples - -Let's explore some examples of the functional differences when using the new `StreamChannelListView`. - -The **StreamChannelListController** provides various methods, such as: - -- **`deleteChannel`** -- **`loadMore`** -- **`muteChannel`** -- **`deleteChannel`** - -For a complete list with additional information, see the code documentation. - -#### Basic Use - -The following code demonstrates the old way of creating a **ChannelListPage**, that displays a list of channels: - -```dart -class ChannelListPage extends StatelessWidget { - const ChannelListPage({ - Key? key, - }) : super(key: key); - - @override - // ignore: prefer_expression_function_bodies - Widget build(BuildContext context) { - return Scaffold( - body: ChannelsBloc( - child: ChannelListView( - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - sort: const [SortOption('last_message_at')], - limit: 20, - channelWidget: const ChannelPage(), - ), - ), - ); - } -} -``` - -In **v4** this can now be achieved with the following: - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - Key? key, - required this.client, - }) : super(key: key); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => Scaffold( - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: const ChannelPage(), - ), - ), - ), - ), - ), - ); -} -``` - -As you can see, the **ChannelsBloc** has been replaced with a **StreamChannelListController**, where the **filter**, **limit**, and **sort** arguments can be set. The above code also demonstrates how to refresh the channel list by calling `_controller.refresh()`. - -## MessageSearchListView to StreamMessageSearchListView - -The `MessageSearchListView` widget has been deprecated, and it is now recommended to use `StreamMessageSearchListView`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `StreamMessageSearchListController`. This controller manages the content when searching for a message; it lets you perform tasks such as: - -- Load initial data. -- Set filters and search terms. -- Load more data using `loadMore`. -- Refresh data. - -For more information see the [`StreamMessageSearchListView` documentation](../../02-stream_chat_flutter/06-message_list/stream_message_search_list_view.mdx). - -### MessageSearchBloc to StreamMessageSearchListController - -The `MessageSearchBloc` widget should be replaced with a `StreamMessageSearchListController`. This controller provides all the functionality needed to query and manipulate message search data previously accessible through `MessageSearchBloc`. - -For more information see the [`StreamMessageSearchListController` documentation](../../04-stream_chat_flutter_core/stream_message_search_list_controller.mdx). - -### StreamMessageSearchListView Example - -The following code demonstrates the old way of searching for messages: - -```dart -class SearchExample extends StatelessWidget { - const SearchExample({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return MessageSearchBloc( - child: MessageSearchListView( - showErrorTile: true, - messageQuery: 'message query', - filters: Filter.in_('members', const ['user-id']), - sortOptions: const [ - SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - pullToRefresh: false, - limit: 30, - emptyBuilder: (context) => const Text('Nothing to show'), - itemBuilder: (context, messageResponse) { - /// Return widget - } - onItemTap: (messageResponse) { - /// Handle on tap - } - ), - ); - } -} -``` - -In **v4**, this can now be achieved with the following: - -```dart -class SearchExample extends StatefulWidget { - const SearchExample({ - Key? key, - }) : super(key: key); - - @override - State createState() => _SearchExampleState(); -} - -class _SearchExampleState extends State { - late final StreamMessageSearchListController _messageSearchListController = - StreamMessageSearchListController( - client: StreamChat.of(context).client, - filter: Filter.in_('members', [StreamChat.of(context).currentUser!.id]), - limit: 5, - searchQuery: '', - sort: [ - const SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - ); - - search() { - _messageSearchListController.searchQuery = 'search-value'; - _messageSearchListController.doInitialLoad(); - } - - @override - dispose() { - _messageSearchListController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return StreamMessageSearchListView( - controller: _messageSearchListController, - emptyBuilder: (context) => const Text('Nothing to show'), - itemBuilder: ( - context, - messageResponses, - index, - defaultWidget, - ) { - return defaultWidget.copyWith(); // modify default widget - }); - } -} -``` - -## UserListView to StreamUserListView - -The `UserListView` widget has been deprecated, and it is now recommended to use `StreamUserListView`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `StreamUserListController`. This controller manages the content when retrieving Stream users; it let's you perform tasks, such as: - -- Load data. -- Set filters. -- Refresh data. - -For more information see the [`StreamUserListView` documentation](../../02-stream_chat_flutter/09-user_list/stream_user_list_view.mdx). - -### UsersBloc to StreamUserListController - -The `UsersBloc` widget should be replaced with a `StreamUserListController`. This controller provides all the functionality needed to query and manipulate user data previously accessible through `UsersBloc`. - -For more information see the [`StreamUserListController` documentation](../../04-stream_chat_flutter_core/stream_user_list_controller.mdx). - -### StreamUserListView Example - -The following code demonstrates the old way of displaying all users: - -```dart -class UsersExample extends StatelessWidget { - const UsersExample({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return UsersBloc( - child: UserListView( - groupAlphabetically: true, - onUserTap: (user, _) { - /// Handle on tap - }, - limit: 25, - filter: Filter.and([ - Filter.autoComplete('name', 'some-name'), - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]), - sort: const [ - SortOption( - 'name', - direction: 1, - ), - ], - ), - ); - } -} -``` - -In **v4**, this can now be achieved with the following: - -```dart -class UsersExample extends StatefulWidget { - const UsersExample({ - Key? key, - }) : super(key: key); - - @override - State createState() => _UsersExampleState(); -} - -class _UsersExampleState extends State { - late final userListController = StreamUserListController( - client: StreamChat.of(context).client, - limit: 25, - filter: Filter.and([ - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]), - sort: [ - const SortOption( - 'name', - direction: 1, - ), - ], - ); - - void _load() { - userListController.filter = Filter.and([ - Filter.autoComplete('name', 'some-name'), - Filter.notEqual('id', StreamChat.of(context).currentUser!.id), - ]); - userListController.doInitialLoad(); - } - - @override - dispose() { - userListController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return StreamUserListView( - controller: userListController, - onUserTap: (user) { - /// Handle on tap - }, - emptyBuilder: (context) => const Text('Nothing to show'), - itemBuilder: ( - context, - users, - index, - defaultWidget, - ) { - return defaultWidget.copyWith(); // modify default widget - }, - ); - } -} -``` - -## MessageInput to StreamMessageInput - -The `MessageInput` widget has been deprecated, and it is now recommended to use `StreamMessageInput`. - -Version 4 of the Stream Chat Flutter packages introduces a new controller called, `MessageInputController`. This controller maintains the state of the message input and exposes various methods to allow you to customize and manipulate the underlying **Message** value. - -Creating a separate controller allows easier control over the message input content by moving logic out of the deprecated `MessageInput` and into the controller. This controller can then be created, managed, and exposed in whatever way you like. - -The widget is also separated into smaller components: `StreamCountDownButton`, `StreamAttachmentPicker`, etc. - -> ❗The `MessageInputController` is exposed by the **`stream_chat_flutter_core`** package. This allows you to use the controller even if you're not using the UI components. - -As a result of this extra control, it is no longer needed for the new `StreamMessageInput` widget to expose these `MessageInput` arguments: - -- `parentMessage`: parent message in case of a thread -- `editMessage`: message to edit -- `initialMessage`: message to start with -- `quotedMessage`: message to quote/reply -- `onQuotedMessageCleared`: callback for clearing quoted message -- `textEditingController`: the text controller of the text field - -The following arguments are newly introduced to the `StreamMessageInput`, and are not available on the old `MessageInput`: - -- `messageInputController`: the controller for the message input -- `attachmentsPickerBuilder`: builder for bottom sheet when attachment picker is opened -- `sendButtonBuilder`: builder for creating send button -- `validator`: a callback function that validates the message -- `restorationId`: restoration ID to save and restore the state of the MessageInput -- `enableSafeArea`: wraps the **StreamMessageInput** widget with a **SafeArea** widget -- `elevation`: elevation of the **StreamMessageInput** widget -- `shadow`: **Shadow** for the **StreamMessageInput** widget - -For more information see the [`StreamMessageInput` documentation](../../04-stream_chat_flutter_core/stream_message_input_controller.mdx). - -### StreamMessageInput Examples - -Let's explore some examples of the functional differences when using the new `StreamMessageInput`. - -#### Basic Use - -Unless you want to programmatically manipulate the value of the message input, then there is no difference in how you would use the message input widget. - -The following code demonstrates the old way of creating a **ChannelPage** widget that displays a chat screen: - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: const ChannelHeader(), - body: Column( - children: const [ - Expanded( - child: MessageListView(), - ), - MessageInput(), - ], - ), - ); - } -} -``` - -In **v4** this is the same, the only difference being that all the Stream widgets are now prefixed with **Stream**. For example, **MessageListView** becomes **StreamMessageListView**, and so forth. - -```dart -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) => Scaffold( - appBar: const StreamChannelHeader(), - body: Column( - children: const [ - Expanded( - child: StreamMessageListView(), - ), - StreamMessageInput(), - ], - ), - ); -} -``` - -However, you can optionally pass in a **MessageInputController** in the **StreamMessageInput**, which gives extra control over the message input value. - -#### Thread Page - -The following code demonstrates the old way of creating a thread page: - -```dart -class ThreadPage extends StatelessWidget { - const ThreadPage({ - Key? key, - this.parent, - }) : super(key: key); - - final Message? parent; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: ThreadHeader( - parent: parent!, - ), - body: Column( - children: [ - Expanded( - child: MessageListView( - parentMessage: parent, - ), - ), - MessageInput( - parentMessage: parent, - ), - ], - ), - ); - } -} -``` - -In **v4** the only difference is the **Stream** prefix and the way that the parent message is passed to the message input: - -```dart -class ThreadPage extends StatelessWidget { - const ThreadPage({ - Key? key, - this.parent, - }) : super(key: key); - - final Message? parent; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: StreamThreadHeader( - parent: parent!, - ), - body: Column( - children: [ - Expanded( - child: StreamMessageListView( - parentMessage: parent, - ), - ), - StreamMessageInput( - messageInputController: MessageInputController( - message: Message(parentId: parent!.id), - ), - ), - ], - ), - ); - } -} -``` - -To send a thread message, you need to specify the message's parent ID for which you're creating a thread. - -#### Reply/Quote Message - -The following code demonstrates the old way of replying to a message: - -```dart -... - -void _reply(Message message) { - setState(() => _quotedMessage = message); -} - -... - -MessageInput - quotedMessage: _quotedMessage, - onQuotedMessageCleared: () { - setState(() => _quotedMessage = null); - }, -), -``` - -To reply to a message in **v4**: - -```dart -... - -void _reply(Message message) { - _messageInputController.quotedMessage = message; -} - -... - -StreamMessageInput( - messageInputController: _messageInputController, -), -``` - -The controller makes it much simpler to dynamically modify the message input. - -## Stream Chat Flutter Core - -Various changes have been made to the Core package, most notably, the introduction of all of the controllers mentioned above. - -These controllers replace the business logic implementations (Bloc). Please note that this is not related to the well-known Flutter Bloc package, but instead refers to the naming we used for our business logic components. - -In this version we're introducing controllers in place of their bloc counterparts: -**StreamChannelListController** in favor of **ChannelsBloc** -**StreamMessageSearchListController** in favor of **MessageSearchBloc** -**StreamUserListController** in favor of **UsersBloc** - -The Bloc components are deprecated in v4.0.0 but can still be used. They will be removed in the next major release (v5.0.0). - -Additionally, we also now have the **StreamMessageInputController**, as discussed above. This can be used outside of our UI package as well. - -Finally, the following Core builders are also deprecated as their functionality can be replaced using their controller counterparts: - -- ChannelListCore -- MessageSearchListCore -- UserListCore diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-migrations/migration_guide_5_0.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-migrations/migration_guide_5_0.mdx deleted file mode 100644 index 553b194754..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-migrations/migration_guide_5_0.mdx +++ /dev/null @@ -1,174 +0,0 @@ ---- -id: migration_guide_5_0 -title: v5.0 -slug: /guides/migration_guide_5_0/ ---- - -**Version 5.0.0** of the Stream Chat Flutter SDK UI package has been overhauled to support larger screen sizes better and provide native feeling web and desktop platform interactions that feel intuitive and expected. - -These newly introduced changes are platform-dependent and will not affect your current Android and iOS builds. - -This guide enumerates and better explains the SDK changes introduced in v5. - -If you find any bugs or have any questions, please file an [issue on our GitHub repository](https://github.com/GetStream/stream-chat-flutter/issues). We want to support you as much as we can with this migration. - -Code examples: - -- See our [Stream Chat Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) for an up-to-date guide using the latest Stream Chat version. -- See the [Stream Flutter Samples repository](https://github.com/GetStream/flutter-samples) with our full fledged messaging [sample application](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). - -Our documentation has also been updated to support v5, so all guides and examples will have updated code. - -### Dependencies - -To migrate to v5.0.0, update your `pubspec.yaml` with the correct Stream chat package you're using: - -```yaml -dependencies: - stream_chat_flutter: ^5.0.0 # full UI, core and client packages - stream_chat_flutter_core: ^5.0.0 # core and client packages - stream_chat: ^5.0.0 # client package -``` - ---- - -## Desktop and Web Support: What Changed? - -This section highlights our efforts on Desktop (macOS, Windows, and Linux) and Web support. - -### Setup - -See the [setup guide](/flutter/v5/stream_chat_flutter/setup) for platform specific instructions. - -### Supporting Larger Screens - -We've added support for larger screens and have made changes to the UI to support larger screen sizes better. - -- Widgets are constrained to a maximum size, for example, appropriate message sizing for larger screens. -- UI changes to use larger screen real estate. For example, reactions are added to the bottom of a message on desktop and web. - -Below is an example running on macOS, with a split-screen view showing channels on the left and messages on the right. - -![MacOS split](../../../../flutter_versioned_docs/version-5.x.x/assets/mac_os_split.png) - -### Native Platform Interactions - -The user experience of interacting with a desktop application differs from a mobile counterpart. There are several factors to consider for an application to feel native and intuitive on the platform it is running, for example: - -- Input controls: touch, keyboard, and mouse interactions -- Native file system or gallery access (as well as sharing functionality) -- Shortcuts -- Dialog screens - -By default, Stream Chat Flutter will use the correct input controls and visual elements for the target platform. For example, touch and swipe controls will be the default on mobile, while on web and desktop these will be disabled and interactions with the mouse and keyboard will be preferred. - -On desktop and web it's also possible to add attachments by simply dragging them into the message input box. - -### All UI/Behaviour Changes for Desktop and Web - -- Right-click context menus for messages and full-screen attachments. -- Upload and download attachments using the native desktop file system. -- Press the "enter" key to send a message. -- If you are quoting a message and have not yet typed any text, you can press the `"esc"` key to remove the quoted message. -- A dedicated "X" button for removing a quoted message with your mouse. -- Drag and drop attachment files to `StreamMessageInput`. -- New `StreamMessageInput.draggingBorder` property to customize the border color of the message input when dropping a file. -- Message reactions bubbles differ per platform. -- Hovering over a message reaction will show the users that have reacted to the message. -- Desktop attachment sharing UI. -- Selectable message text with mouse input. -- Gallery navigation controls with keyboard shortcuts (left and right arrow keys). -- Appropriate message sizing for large screens. -- Right-click context menu for `StreamMessageListView` items. -- `StreamMessageListView` items not swipe-able on desktop & web. -- Video support for Windows & Linux through `dart_vlc`. -- Video support for macOS through `video_player_macos`. -- Replace bottom sheets with dialog screens where appropriate. - -## What's New? - -We improved the overall user experience of the Stream Chat Flutter SDK and added new features to make it easier to customize the SDK to your needs. - -We've also fixed several bugs and improved the overall stability of the SDK. - -### StreamChatConfiguration - -The `StreamChatConfiguration` class is a new inherited widget that allows you to configure the Stream Chat Flutter SDK. - -It provides a few configuration options. For example, it lets you specify if you want to `enforceUniqueReactions` or not and allows you to set the `reactionIcons` to use in your app. - -You can retrieve the current configuration using `StreamChatConfiguration.of(context)`, as long as there is a `StreamChat` or `StreamChatConfiguration` widget higher up the widget tree. You can provide a custom `StreamChatConfigurationData` directly to `StreamChat` or wrap a section of the widget tree with a `StreamChatConfiguration`. - -For additional information, see [#1125](https://github.com/GetStream/stream-chat-flutter/issues/1125). The `defaultUserImage`, `placeholderUserImage`, `reactionIcons`, and `enforceUniqueReactions` have been refactored out of `StreamChatThemeData` and into the new`StreamChatConfigurationData` class. - -### StreamMemberListView and StreamMemberGridView - -The `StreamMemberListView` and `StreamMemberGridView` widgets are new widgets that allow you to display a list of members in a channel. - -Check out the dedicated [documentation](/flutter/v5/stream_chat_flutter/stream_member_list_view) for more information. - -### Attachment Picker - -As part of the v5 release, we've refactored the `AttachmentPicker` to be more flexible and customizable. This allows you to use the `AttachmentPicker` in various ways and customize the UI to your liking. - -Check out the dedicated [guide](/flutter/v5/customization/custom-widgets/customize_attachment_picker_modal) for more information. - -### Other Changes - -The following was also introduced: - -- Added support for additional text field parameters in`StreamMessageInput`: `maxLines`, `minLines`, `textInputAction`, `keyboardType`, and `textCapitalization`. -- Added `showStreamAttachmentPickerModalBottomSheet` to show the attachment picker modal bottom sheet. -- Added `onQuotedMessageCleared` to `StreamMessageInput` -- `selected` and `selectedTileColor` to `StreamChannelListTile` -- Added `AttachmentUploadStateBuilder.inProgressBuilder` to `AttachmentUploadStateBuilder` -- Added `AttachmentUploadStateBuilder.successBuilder` to `AttachmentUploadStateBuilder` -- Added `AttachmentUploadStateBuilder.failedBuilder` to `AttachmentUploadStateBuilder` -- Added `StreamAutocomplete` widget for auto-complete triggers in `StreamMessageInput`. -- Added `StreamMessageInput.customAutocompleteTriggers` to allow users to define their custom triggers. - -New translations: - -- `couldNotReadBytesFromFileError` -- `downloadLabel` -- `toggleMuteUnmuteAction` -- `toggleMuteUnmuteGroupQuestion` -- `toggleMuteUnmuteGroupText` -- `toggleMuteUnmuteUserQuestion` -- `toggleMuteUnmuteUserText` - -## Deprecated - -The following components have been deprecated in v5.0.0: - -- Deprecated `showConfirmationDialog` in favor of `showConfirmationBottomSheet` -- Deprecated `showInfoDialog` in favor of `showInfoBottomSheet` -- Deprecated `wrapAttachmentWidget` in favor of the `WrapAttachmentWidget` class - -## Breaking changes - -The following components have been removed in v5.0.0: - -- `StreamImageAttachment.size` has been removed in favor of `StreamImageAttachment.constraints`. -- `StreamFileAttachment.size` has been removed in favor of `StreamFileAttachment.constraints`. -- `StreamGiphyAttachment.size` has been removed in favor of `StreamGiphyAttachment.constraints`. -- `StreamVideoAttachment.size` has been removed in favor of `StreamVideoAttachment.constraints`. -- `StreamVideoThumbnailImage.width` and `StreamVideoThumbnailImage.height` have been removed in favor of `StreamVideoThumbnailImage.constraints`. - -To fix these deprecations in your code, you can use a `BoxConstraints.tight` passing the desired fixed size as a parameter. - -```dart -/// BEFORE -StreamImageAttachment( - size: size, -) - -/// AFTER -StreamImageAttachment( - constraints: BoxConstraints.tight(size), -) -``` - -- Removed `StreamMessageInput.customOverlays` in favor of `StreamMessageInput.customAutocompleteTriggers`. Read the guide on [Adding Custom Autocomplete Triggers](/flutter/v5/customization/custom-widgets/autocomplete_triggers) to learn how to migrate your code. - -- Removed the default emoji overlay picker. Read the guide on [Adding Custom Autocomplete Triggers](/flutter/v5/customization/custom-widgets/autocomplete_triggers) to learn how to migrate your code. diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-migrations/migration_guide_7_0.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-migrations/migration_guide_7_0.mdx deleted file mode 100644 index ad2d6dcc0f..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-migrations/migration_guide_7_0.mdx +++ /dev/null @@ -1,158 +0,0 @@ ---- -id: migration_guide_7_0 -title: v7.0 -slug: /guides/migration_guide_7_0/ ---- - -This guide enumerates and better explains the SDK changes introduced in v7. - -If you find any bugs or have any questions, please file an [issue on our GitHub repository](https://github.com/GetStream/stream-chat-flutter/issues). We want to support you as much as we can with this migration. - -Code examples: - -- See our [Stream Chat Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) for an up-to-date guide using the latest Stream Chat version. -- See the [Stream Flutter Samples repository](https://github.com/GetStream/flutter-samples) with our full fledged messaging [sample application](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). - -Our documentation has also been updated to support v7, so all guides and examples will have updated code. - -### Dependencies - -To migrate to v7.0.0, update your `pubspec.yaml` with the correct Stream chat package you're using: - -```yaml -dependencies: - stream_chat_flutter: ^7.0.0 # full UI, core and client packages - stream_chat: ^7.0.0 # client package -``` - ---- - -## What's New? - -We improved the overall user experience of the Stream Chat Flutter SDK and added new features to make it easier to customize the SDK to your needs. - -We've also fixed several bugs and improved the overall stability of the SDK. - -Added support for `StreamMessageInput.contentInsertionConfiguration` to specify the content insertion configuration. - - ```dart - StreamMessageInput( - ..., - contentInsertionConfiguration: ContentInsertionConfiguration( - onContentInserted: (content) { - // Do something with the content. - controller.addAttachment(...); - }, - ), - ) - ``` -## Breaking changes - -The following components have been removed in v7.0.0: - -- `ChatPersistenceClient.getChannelStates.sort` has been removed in favor of `ChatPersistenceClient.getChannelStates.channelStateSort`. -```dart -/// BEFORE -chatPersistenceClient.getChannelStates( - ... - sort: [SortOption('last_message_at')], -) - -/// AFTER -chatPersistenceClient.getChannelStates( - ... - channelStateSort: [SortOption('last_message_at')], -) -``` -- `StreamChatClient.queryChannels.sort` has been removed in favor of `StreamChatClient.queryChannels.channelStateSort`. -```dart -/// BEFORE -streamChatClient.getChannelStates( - ... - sort: [SortOption('last_message_at')], -) - -/// AFTER -streamChatClient.getChannelStates( - ... - channelStateSort: [SortOption('last_message_at')], -) -``` -- `MessageWidget.customAttachmentBuilders` has been removed in favor of `MessageWidget.attachmentBuilders`. -```dart -/// BEFORE -MessageWidget( - customAttachmentBuilders: { - 'image': (context, message, attachment) => // build image attachment, - }, - ... -) -``` -```dart -/// AFTER -class CustomImageAttachmentBuilder extends StreamAttachmentWidgetBuilder { - @override - bool canHandle( - Message message, - Map> attachments, - ) { - // Custom logic to check - // if the attachment can be handled by this builder - ... - } - - @override - Widget build( - BuildContext context, - Message message, - Map> attachments, - ) { - // custom build implementation - ... - } -} - -MessageWidget( - attachmentBuilders: const [CustomImageAttachmentBuilder()], - ... -) -``` -- `RetryPolicy.retryTimeout` has been removed in favor of `RetryPolicy.delayFactor`. -- `StreamChatNetworkError.fromDioError` has been removed in favor of `StreamChatNetworkError.fromDioException`. -- `MessageSendingStatus` has been removed in favor of `MessageState`. -- `StreamChannelListController.sort` has been removed in favor of `StreamChannelListController.channelStateSort`. -- `ChannelPreview` has been removed in favor of `StreamChannelListTile`. -- `ChannelPreviewBuilder` has been removed in favor of `StreamChannelListViewIndexedWidgetBuilder`. -- `StreamUserItem` has been removed in favor of `StreamUserListTile`. -- `ReturnActionType` has been removed and no longer used. -- `StreamMessageInput.attachmentThumbnailBuilders` has been removed in favor of `StreamMessageInput.mediaAttachmentBuilder`. -- `MessageWidget.showReactionPickerIndicator` has been removed in favor of `MessageWidget.showReactionPicker`. -- `MessageWidget.bottomRowBuilder` has been removed in favor of `MessageWidget.bottomRowBuilderWithDefaultWidget`. -- `MessageWidget.deletedBottomRowBuilder` has been removed in favor of `MessageWidget.deletedBottomRowBuilderWithDefaultWidget`. -- `MessageWidget.usernameBuilder` has been removed in favor of `MessageWidget.usernameBuilderWithDefaultWidget`. -- `MessageWidget.showReactionPickerTail` has been removed in favor of `MessageWidget.showReactionPicker`. -- `MessageTheme.linkBackgroundColor` has been removed in favor of `MessageTheme.urlAttachmentBackgroundColor`. -- `showConfirmationDialog` has been removed in favor of `showConfirmationBottomSheet`. -- `showInfoDialog` has been removed in favor of `showInfoBottomSheet`. -- `wrapAttachmentWidget` has been removed in favor of `WrapAttachmentWidget`. -- `MessageListView.onMessageSwiped` parameter. Try wrapping the `MessageWidget` with a `Swipeable`, `Dismissible` or a custom widget to achieve the swipe to reply behaviour. -```dart -/// BEFORE -MessageListView( - onMessageSwiped: (Message message) => // handle swipe, - ... -) - -/// AFTER -MessageListView( - messageBuilder: (BuildContext context, Message message) => - Swipeable( - key: ValueKey(message.id), - onSwiped: (_) => // handle swipe, - child: StreamMessageWidget( - message: message, - ... - ), - ), -) -``` diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-migrations/migration_guide_8_0.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-migrations/migration_guide_8_0.mdx deleted file mode 100644 index e8f97bfc35..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/08-migrations/migration_guide_8_0.mdx +++ /dev/null @@ -1,57 +0,0 @@ ---- -id: migration_guide_8_0 -title: v8.0 -slug: /guides/migration_guide_8_0/ ---- - -This guide enumerates and better explains the SDK changes introduced in v8. - -If you find any bugs or have any questions, please file an [issue on our GitHub repository](https://github.com/GetStream/stream-chat-flutter/issues). We want to support you as much as we can with this migration. - -Code examples: - -- See our [Stream Chat Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) for an up-to-date guide using the latest Stream Chat version. -- See the [Stream Flutter Samples repository](https://github.com/GetStream/flutter-samples) with our full fledged messaging [sample application](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). - -Our documentation has also been updated to support v8, so all guides and examples will have updated code. - -### Dependencies - -To migrate to v8.0.0, update your `pubspec.yaml` with the correct Stream chat package you're using: - -```yaml -dependencies: - stream_chat_flutter: ^8.0.0 # full UI, core and client packages - stream_chat: ^8.0.0 # client package -``` - ---- - -## Important notes - -- The package from recent versions has been restricted to Flutter 3.19+ as we generally aim to support -the latest and the previous version of Flutter when possible. - -- The `attachmentBuilders` parameter in the `StreamMessageListView` now only expect custom attachments -and does not need the default attachment builders. You can also use `StreamAttachmentWidgetBuilder.defaultBuilders` -to add the default builders if necessary. - -## Breaking changes - -Version 8.0 has two main breaking changes. - -### Removal of the `useMaterial3` flag - -In v7, we introduced a temporary `useMaterial3` flag that allows users to optionally use Material3 styling in Stream components. -This was necessary at the time for various reasons. - -However, this flag is now removed and Material3 will be the default styling for all components. - -### Connectivity stream changes - -While this is a not directly a user-facing change, it is added here for completeness of the list. - -The `StreamChat` widget has a `connectivityStream` parameter to allow testing of various scenarios. -Due to changes in the relevant package, it was necessary to change the type of the stream from -`Stream?` to `Stream>?`. - diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/09-initialize_stream_chat_widget_tree.mdx b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/09-initialize_stream_chat_widget_tree.mdx deleted file mode 100644 index 9207d4585a..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/09-initialize_stream_chat_widget_tree.mdx +++ /dev/null @@ -1,699 +0,0 @@ ---- -id: initialize_stream_chat_widget_tree -title: Initialize Stream Chat in Part of the Widget Tree ---- - -If you’re creating a full-scale chat application, you probably want to have Stream Chat Flutter initialized at the top of your widget tree and the Stream user connected as soon as they open the application. - -However, if you only need chat functionality in a part of your application, then it’ll be better to delay Stream Chat initialization to when it’s needed. -This guide demonstrates three alternative ways for you to initialize Stream Chat Flutter for a part of your widget tree and to only connect a user when needed. - -## What To Keep In Mind? - -Before investigating potential solutions, let’s first take a look at the relevant Stream Chat widgets and classes. - -Most of the Stream Chat Flutter UI widgets rely on having a [StreamChat](../02-stream_chat_flutter/stream_chat_and_theming.mdx) ancestor in the widget tree. -The **StreamChat** widget is an [InheritedWidget](https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html) that exposes the **StreamChatClient** through **BuildContext**. -This widget also initializes the [StreamChatCore](../04-stream_chat_flutter_core/stream_chat_core.mdx) widget and the **StreamChatTheme**. - -**StreamChatCore** is a **StatefulWidget** used to react to life cycle changes and system updates. -When the app goes into the background, the WebSocket connection is closed. -Conversely, a new connection is initiated when the app is back in the foreground. - -What is important to take note of is that **a connection is only established if a user is connected**. - -This means that if you have not yet called `client.connectUser(user, token)`, no connection will be made, and only background listeners will be registered to determine the app's foreground state. - -## Option 1: Builder and Connect/Disconnect User - -This option requires you to wrap your whole application with the **StreamChat** widget and to call `connectUser` and `disconnectUser` as needed. - -This option is the easiest, however, it requires **StreamChat** to be at the top of each route and as a result, will have a slight overhead as it’ll create the above-mentioned Stream widgets that may not yet be needed. - -### Exposing the StreamChat Widget - -First, you must expose the client and base Stream Chat widgets to the whole application. - -```dart -void main() { - final client = StreamChatClient( - 'q29npdvqjr99', - logLevel: Level.OFF, - ); - - 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) { - return StreamChat(client: client, child: child); - }, - home: const HomeScreen(), - ); - } -} -``` - -In the above code, you: - -1. Create a **StreamChatClient** instance -2. Pass the instance to the **StreamChat** widget -3. Expose **StreamChat** to the whole application within the **MaterialApp** `builder` - -A few important things to note: - -- The `builder` wraps the **StreamChat** widget for every route of our application. No matter where you are in the widget tree, you’ll be able to call `StreamChat.of(context)`. -- The state will only be created once for our application, as **StreamChat** is a **StatefulWidget** and the position of **StreamChat** in the widget tree remains the same throughout the application lifecycle. -- No connection will be made until you call `connectUser`. - -### Connecting and Disconnecting Users - -In **MaterialApp** above, the home page is set to **HomeScreen**. This screen could look something like the following: - -```dart -class HomeScreen extends StatelessWidget { - const HomeScreen({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(), - body: const Center( - child: Text('Home Screen'), - ), - floatingActionButton: FloatingActionButton( - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute(builder: (context) => const ChatSetup())); - }, - child: const Icon( - Icons.message, - ), - ), - ); - } -} -``` - -This screen shows a floating action button that on click navigates the user to the **ChatSetup**. We want to connect and disconnect a Stream user only when they go to the chat setup screen. - -```dart -class ChatSetup extends StatefulWidget { - const ChatSetup({ - super.key, - }); - - @override - State createState() => _ChatSetupState(); -} - -class _ChatSetupState extends State { - late final Future connectionFuture; - late final client = StreamChat.of(context).client; - - @override - void initState() { - super.initState(); - connectionFuture = client.connectUser( - User(id: 'USER_ID'), - 'TOKEN', - ); - } - - @override - void dispose() { - client.disconnectUser(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(), - body: FutureBuilder( - future: connectionFuture, - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return const Center( - child: CircularProgressIndicator(), - ); - default: - if (snapshot.hasError) { - return Text('Error: ${snapshot.error}'); - } else { - return const ChannelListPage(); - } - } - }, - ), - ); - } -} -``` - -Within `initState` you call `connectUser`; once the future for `connectUser` has completed a connection to the Stream API is established, you can then display the relevant Stream Chat UI widgets. - -Once the **ChatScreen** widget is disposed of, then `disconnectUser` will be called within the `dispose` method. - -### Caution - -In this example, `disconnectUser` will **only** be called when the **ChatSetup** widget is disposed. - -You need to ensure that this widget (route) is completely disposed of, or you need to call `disconnectUser` and `connectUser` manually when navigating to relevant parts of your application. - -For example, let’s say you have a button within one of the chat screens to navigate to a completely different part of your app, then you want to make sure the **ChatScreen** route is disposed of by forcing it to be removed: - -```dart -Navigator.of(context).pushAndRemoveUntil( - MaterialPageRoute( - builder: ((context) => const HomeScreen()), - ), - (Route route) => false, -); -``` - -Or let’s say you wanted to pop back to the first route: - -```dart -Navigator.of(context).popUntil((route) => route.isFirst); -``` - -Both of these will ensure the route is disposed of and the user is disconnected as a result. - -## Option 2: A Nested Navigator - -Another approach would be to introduce a new [Navigator](https://api.flutter.dev/flutter/widgets/Navigator-class.html). -This has the benefit that everything related to Stream chat is contained to a specific part of the widget tree. - -### Defining Routes and Nested Routes - -In this example, our application has the following routes. - -```dart -const routeHome = '/'; -const routePrefixChat = '/chat/'; -const routeChatHome = '$routePrefixChat$routeChatChannels'; -const routeChatChannels = 'chat_channels'; -const routeChatChannel = 'chat_channel'; -``` - -For the `/chat/` nested routes (**routePrefixChat**), this approach initializes Stream Chat in our application and introduces a nested navigator. - -Let’s explore the code: - -```dart -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatefulWidget { - const MyApp({ - Key? key, - }) : super(key: key); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - final GlobalKey navigatorKey = GlobalKey(); - - @override - Widget build(BuildContext context) { - return Provider.value( - value: navigatorKey, - child: MaterialApp( - navigatorKey: navigatorKey, - initialRoute: routeHome, - onGenerateRoute: (settings) { - late Widget page; - if (settings.name == routeHome) { - page = const HomeScreen(); - } else if (settings.name!.startsWith(routePrefixChat)) { - final subRoute = settings.name!.substring(routePrefixChat.length); - page = ChatSetup( - setupChatRoute: subRoute, - ); - } else { - throw Exception('Unknown route: ${settings.name}'); - } - - return MaterialPageRoute( - builder: (context) { - return page; - }, - settings: settings, - ); - }, - ), - ); - } -} -``` - -In the above code you’re: - -1. Creating a navigator key, passing it to `MaterialApp`, and exposing it to the whole application using Provider (you can expose it however you want). -2. Creating `onGenerateRoute` that specifies what page to show depending on the route. Most importantly, if the route contains the **routePrefixChat,** it navigates to the **ChatSetup** page and passes in the remainder of the route. - -For example, `Navigator.pushNamed(context, routeChatHome)` will navigate to the **ChatSetup** page and pass in the nested route **routeChatChannels.** - -### Stream Chat Initialization, User Connection, and Nested Navigation - -Within the **ChatSetup** widget, we’ll initialize Stream chat, connect a user, and create a new Navigator that handles the sub-navigation for the chat-specific pages. - -```dart -class ChatSetup extends StatefulWidget { - const ChatSetup({Key? key, required this.setupChatRoute}) : super(key: key); - - final String setupChatRoute; - - @override - State createState() => _ChatSetupState(); -} - -class _ChatSetupState extends State { - late final Future connectionFuture; - late final client = StreamChatClient( - 'KEY', - logLevel: Level.OFF, - ); - - @override - void initState() { - super.initState(); - connectionFuture = client.connectUser( - User(id: 'USER_ID'), - 'TOKEN', - ); - } - - @override - void dispose() { - client.disconnectUser(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Material( - child: StreamChat( - client: client, - child: FutureBuilder( - future: connectionFuture, - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return const Center( - child: CircularProgressIndicator(), - ); - default: - if (snapshot.hasError) { - return Text('Error: ${snapshot.error}'); - } else { - return Navigator( - initialRoute: widget.setupChatRoute, - onGenerateRoute: _onGenerateRoute, - ); - } - } - }, - ), - ), - ); - } - - Route _onGenerateRoute(RouteSettings settings) { - late Widget page; - switch (settings.name) { - case routeChatChannels: - page = ChannelListPage( - client: client, - ); - break; - case routeChatChannel: - final channel = settings.arguments as Channel; - page = StreamChannel( - channel: channel, - child: const ChannelPage(), - ); - break; - default: - throw Exception('Unknown route: ${settings.name}'); - } - return MaterialPageRoute( - builder: (context) { - return page; - }, - settings: settings, - ); - } -} -``` - -This **ChatSetup** widget is similar to what it was in the first option, the only difference is that we’re also introducing a nested navigator and handling those nested routes. - -The steps for the above code are: - -1. Create a **StreamChatClient** instance -2. Call `connectUser` within `initState` and await the result using a **FutureBuilder** -3. Introduce a **StreamChat** widget into the widget tree -4. Introduce a new **Navigator** for the chat-specific routes -5. Call `disconnectUser` within `dispose` - -### Displaying Stream Chat UI Widgets and Global Navigation - -Then finally, the **ChannelListPage** could look something like the following: - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - super.key, - required this.client, - }); - - final StreamChatClient client; - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final _controller = StreamChannelListController( - client: widget.client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - void _popChatPages() { - final nav = context.read>(); - nav.currentState!.pop(); - } - - @override - Widget build(BuildContext context) { - return WillPopScope( - onWillPop: () async { - _popChatPages(); - return true; - }, - child: Scaffold( - appBar: AppBar( - leading: BackButton( - onPressed: () { - _popChatPages(); - }, - ), - ), - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) { - Navigator.pushNamed(context, routeChatChannel, - arguments: channel); - }, - ), - ), - ), - ); - } -} -``` - -There are two important things to note in the above code: - -- We’re accessing the global **NavigatorState** using Provider and calling `pop()` on the back press. This will ensure that this entire route is disposed of and that the Stream connection is closed. -- Within `onChannelTap` we’re calling `pushNamed` and passing in the route to display a single channel page. This uses the navigator introduced in **ChatSetup**, which is the closest navigator within the widget tree. - -A few things to take note of: - -- You’ll always need to access the global navigator if you want to dispose of this route. you need to ensure that this route is popped or replaced, otherwise, the Stream connection will remain active for as long as the chat route is on the stack (or manually disconnected). - -## Option 3: Navigator 2.0 - Using GoRouter - -This final example will be a combination of the first two options. The following code is an example of how to initialize Stream Chat in a part of the widget tree using the [GoRouter package](https://pub.dev/packages/go_router). This solution will change depending on how you do routing in your Flutter application and which package (if any) you use. - -### Application Routes and Conditional Stream Initialization - -For this example we have the following routes and nested routes: - -```dart -|_ '/' -> home page - |_ 'settings/' - settings page - |_ 'chat/' - chat home, shows the channels list page - |_ 'channel/' - specific channel page -``` - -In the **MyApp** widget, we’ll initialize **GoRouter** and the **StreamChatClient**. -However, we will only expose the **StreamChat** widget for certain routes. -Additionally, we’ll create a **ChatSetup** widget that connects and disconnects the user. -This widget will also **only** be injected for the `/chat` routes. - -```dart -class MyApp extends StatefulWidget { - const MyApp({ - Key? key, - }) : super(key: key); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - final _client = StreamChatClient( - 'q29npdvqjr99', - logLevel: Level.OFF, - ); - bool wasPreviousRouteChat = false; - - late final _router = GoRouter( - initialLocation: '/', - routes: [ - ShellRoute( - builder: (context, state, child) { - if (state.uri.host.startsWith('/chat')) { - wasPreviousRouteChat = true; - return StreamChat( - client: _client, - child: ChatSetup(client: _client, child: child), - ); - } else { - if (wasPreviousRouteChat) { - wasPreviousRouteChat = false; - return StreamChat( - client: _client, - child: child, - ); - } else { - return child; - } - } - }, - routes: [ - GoRoute( - path: '/', - builder: (context, state) => const HomeScreen(), - routes: [ - GoRoute( - path: 'settings', - builder: (context, state) => const SettingsPage(), - ), - GoRoute( - path: 'chat', - builder: (context, state) => const ChannelListPage(), - routes: [ - GoRoute( - path: 'channel', - builder: (context, state) { - final channel = state.extra as Channel; - return StreamChannel( - channel: channel, - child: const ChannelPage(), - ); - }, - ), - ], - ), - ], - ), - ], - ), - ], - ); - - @override - Widget build(BuildContext context) { - return MaterialApp.router( - routeInformationParser: _router.routeInformationParser, - routeInformationProvider: _router.routeInformationProvider, - routerDelegate: _router.routerDelegate, - ); - } -} -``` - -If you’re unfamiliar with GoRouter it will help to first read the documentation and then come back to this guide. - -There are a few important things to note in the above code: - -- Define our routes and nested routes -- Specify the initial route with `initialLocation` -- Use the `navigatorBuilder` to wrap certain routes with **StreamChat** and **ChatSetup**. - - The `wasPreviousRouteChat` \***\*boolean is used to determine if the previous route was a chat route. This is important because when you press the back button from the `/chat` route and navigate to the `/` route, the **StreamChat** widget still needs to be accessible while the navigation transition occurs. However, if you then navigate to the `/setting` route, you no longer need the **StreamChat\*\* widget and can safely remove it. - -### Navigating With GoRouter - -Within the **HomeScreen** you can create a button that on press navigates to the `/chat` route: - -```dart -GoRouter.of(context).go('/chat'); -``` - -### Connecting and Disconnecting Users - -Same as before, we’ll use the **ChatSetup** widget to connect and disconnect a user. -This time the widget also takes in a **child** widget to display once the connection is finished. -The child widget is dependent on the route we’re navigating to. - -```dart -class ChatSetup extends StatefulWidget { - const ChatSetup({ - Key? key, - required this.client, - required this.child, - }) : super(key: key); - - final StreamChatClient client; - final Widget child; - - @override - State createState() => _ChatSetupState(); -} - -class _ChatSetupState extends State { - late final Future connectionFuture; - - @override - void initState() { - super.initState(); - connectionFuture = widget.client.connectUser( - User(id: 'USER_ID'), - 'TOKEN', - ); - } - - @override - void dispose() { - widget.client.disconnectUser(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Material( - child: FutureBuilder( - future: connectionFuture, - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return const Center( - child: CircularProgressIndicator(), - ); - default: - if (snapshot.hasError) { - return Text('Error: ${snapshot.error}'); - } else { - return widget.child; - } - } - }, - ), - ); - } -} -``` - -This will connect the Stream chat user within `initState` and disconnect the user on `dispose`. This is similar to the previous examples we explored. - -### Displaying the Stream UI Widgets - -The **ChannelListPage** can look something like the following: - -```dart -class ChannelListPage extends StatefulWidget { - const ChannelListPage({ - super.key, - }); - - @override - State createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - late final client = StreamChat.of(context).client; - late final _controller = StreamChannelListController( - client: client, - filter: Filter.in_( - 'members', - [StreamChat.of(context).currentUser!.id], - ), - channelStateSort: const [SortOption('last_message_at')], - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(), - body: RefreshIndicator( - onRefresh: _controller.refresh, - child: StreamChannelListView( - controller: _controller, - onChannelTap: (channel) { - GoRouter.of(context).go('/chat/channel', extra: channel); - }, - ), - ), - ); - } -} -``` - -This is the same as before, the only difference is that the navigation is slightly different; now we’re navigating to the `/chat/channel` route for individual channel pages. - -## Conclusion - -This guide demonstrated three different ways to initialize Stream Chat in a part of the Flutter widget tree. - -There are two key takeaways - -1. Accessing **StreamChat** depends on your location in the widget tree -2. How you ultimately decide to expose **StreamChat** and connect users will be up to your application architecture and how you manage routing. - -The above are only examples that can be refined and tweaked to suit your needs. diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/_category_.json b/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/_category_.json deleted file mode 100644 index 14a4f173f0..0000000000 --- a/docusaurus/flutter_versioned_docs/version-7.x.x/05-guides/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Guides" -} \ No newline at end of file diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/authentication_demo_app.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/authentication_demo_app.jpg deleted file mode 100644 index eed57c3374..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/authentication_demo_app.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_header.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_header.png deleted file mode 100644 index 98f41c614b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_header.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_header_custom_title.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_header_custom_title.png deleted file mode 100644 index 65a9ee75a6..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_header_custom_title.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_list_header.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_list_header.png deleted file mode 100644 index 6f112db9be..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_list_header.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_list_header_custom_subtitle.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_list_header_custom_subtitle.png deleted file mode 100644 index 3c7798570a..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_list_header_custom_subtitle.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_list_view.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_list_view.png deleted file mode 100644 index a4390c2eac..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_preview.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_preview.png deleted file mode 100644 index 39f5629bb8..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/channel_preview.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/chat_basics.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/chat_basics.png deleted file mode 100644 index 82e27cfa49..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/chat_basics.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png deleted file mode 100644 index 9e92437dbf..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/chat_overview_page-2fbd5bbfb70c5623bd37ff7d6c41bf4d.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/dashboard_firebase_enable.jpeg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/dashboard_firebase_enable.jpeg deleted file mode 100644 index e4696ec882..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/dashboard_firebase_enable.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/dashboard_firebase_key.jpeg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/dashboard_firebase_key.jpeg deleted file mode 100644 index 87243e91f6..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/dashboard_firebase_key.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/dashboard_save_changes.jpeg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/dashboard_save_changes.jpeg deleted file mode 100644 index 1c58a93e63..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/dashboard_save_changes.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/end_to_end_encryption.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/end_to_end_encryption.png deleted file mode 100644 index b41e11ced6..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/end_to_end_encryption.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/firebase_authentication_dashboard.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/firebase_authentication_dashboard.jpg deleted file mode 100644 index c304055768..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/firebase_authentication_dashboard.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/firebase_cloud_secrets_management.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/firebase_cloud_secrets_management.jpg deleted file mode 100644 index 4f131df4cc..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/firebase_cloud_secrets_management.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png deleted file mode 100644 index c5670d0dc2..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/firebase_notifications_toggle-5aeabfcbdc24cb8f1fea7d41d0e845fc.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/firebase_project_settings.jpeg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/firebase_project_settings.jpeg deleted file mode 100644 index 4fbc6521c3..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/firebase_project_settings.jpeg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/firebase_stream_chat_extension_usage.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/firebase_stream_chat_extension_usage.jpg deleted file mode 100644 index 7374a67f8a..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/firebase_stream_chat_extension_usage.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/hashtag_example.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/hashtag_example.jpg deleted file mode 100644 index a2bb3ba4c9..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/hashtag_example.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/install_stream_chat_firebase_extension.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/install_stream_chat_firebase_extension.jpg deleted file mode 100644 index 309ecce13c..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/install_stream_chat_firebase_extension.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/live_stream_1.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/live_stream_1.jpg deleted file mode 100644 index bef68c6edb..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/live_stream_1.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/live_stream_2.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/live_stream_2.jpg deleted file mode 100644 index 02a3513297..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/live_stream_2.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/localization_support.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/localization_support.jpg deleted file mode 100644 index 50d8b761ee..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/localization_support.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/location_sharing_example.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/location_sharing_example.jpg deleted file mode 100644 index 7f220379c9..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/location_sharing_example.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/location_sharing_example_message.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/location_sharing_example_message.jpg deleted file mode 100644 index 707f138876..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/location_sharing_example_message.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/location_sharing_example_message_thumbnail.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/location_sharing_example_message_thumbnail.jpg deleted file mode 100644 index e2b7d624f5..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/location_sharing_example_message_thumbnail.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/mac_os_split.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/mac_os_split.png deleted file mode 100644 index 7861d54c01..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/mac_os_split.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_actions.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_actions.jpg deleted file mode 100644 index dcfba64ec2..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_actions.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_input.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_input.png deleted file mode 100644 index d63cfbb3e2..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_input.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_input_change_position.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_input_change_position.png deleted file mode 100644 index 859107d25b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_input_change_position.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_input_quoted_message.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_input_quoted_message.png deleted file mode 100644 index c1fda2237b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_input_quoted_message.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_list_view.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_list_view.png deleted file mode 100644 index cc27be3c9b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_list_view_pin.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_list_view_pin.png deleted file mode 100644 index 0b6f1c391f..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_list_view_pin.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_list_view_threads.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_list_view_threads.png deleted file mode 100644 index 2c9387663f..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_list_view_threads.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_reaction_theming.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_reaction_theming.png deleted file mode 100644 index 8cddd6ba22..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_reaction_theming.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_rounded_avatar.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_rounded_avatar.png deleted file mode 100644 index ec3733443a..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_rounded_avatar.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_search_list_view.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_search_list_view.png deleted file mode 100644 index b13f5bdc95..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_search_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_styles.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_styles.png deleted file mode 100644 index db04865c05..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_styles.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_theming.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_theming.png deleted file mode 100644 index b5d28dde0a..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_theming.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_widget_actions.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_widget_actions.png deleted file mode 100644 index e835a4ed04..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/message_widget_actions.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/sdk_title.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/sdk_title.png deleted file mode 100644 index 4d92e89142..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/sdk_title.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/server_key.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/server_key.png deleted file mode 100644 index f11d6fb56b..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/server_key.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/slidable_demo.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/slidable_demo.jpg deleted file mode 100644 index 4cbda5d738..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/slidable_demo.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/stream_chat_app_access_keys.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/stream_chat_app_access_keys.jpg deleted file mode 100644 index 1a869cc810..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/stream_chat_app_access_keys.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/stream_chat_user_database.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/stream_chat_user_database.jpg deleted file mode 100644 index fcfe73c82c..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/stream_chat_user_database.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/stream_firebase_extension_configuration.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/stream_firebase_extension_configuration.jpg deleted file mode 100644 index 0c2129319c..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/stream_firebase_extension_configuration.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/swipe_channel.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/swipe_channel.png deleted file mode 100644 index 44f13ca594..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/swipe_channel.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/user_list_view.png b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/user_list_view.png deleted file mode 100644 index 9aede8243d..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/user_list_view.png and /dev/null differ diff --git a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/using_theme.jpg b/docusaurus/flutter_versioned_docs/version-7.x.x/assets/using_theme.jpg deleted file mode 100644 index b835d9316d..0000000000 Binary files a/docusaurus/flutter_versioned_docs/version-7.x.x/assets/using_theme.jpg and /dev/null differ diff --git a/docusaurus/flutter_versioned_sidebars/version-3.x.x-sidebars.json b/docusaurus/flutter_versioned_sidebars/version-3.x.x-sidebars.json deleted file mode 100644 index 6a5949a0e7..0000000000 --- a/docusaurus/flutter_versioned_sidebars/version-3.x.x-sidebars.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version-3.x.x/defaultSidebar": [ - { - "type": "autogenerated", - "dirName": "." - } - ] - } \ No newline at end of file diff --git a/docusaurus/flutter_versioned_sidebars/version-4.x.x-sidebars.json b/docusaurus/flutter_versioned_sidebars/version-4.x.x-sidebars.json deleted file mode 100644 index bfa90bffb6..0000000000 --- a/docusaurus/flutter_versioned_sidebars/version-4.x.x-sidebars.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version-4.x.x/defaultSidebar": [ - { - "type": "autogenerated", - "dirName": "." - } - ] - } \ No newline at end of file diff --git a/docusaurus/flutter_versioned_sidebars/version-5.x.x-sidebars.json b/docusaurus/flutter_versioned_sidebars/version-5.x.x-sidebars.json deleted file mode 100644 index f1be969d1b..0000000000 --- a/docusaurus/flutter_versioned_sidebars/version-5.x.x-sidebars.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version-5.x.x/defaultSidebar": [ - { - "type": "autogenerated", - "dirName": "." - } - ] - } \ No newline at end of file diff --git a/docusaurus/flutter_versioned_sidebars/version-7.x.x-sidebars.json b/docusaurus/flutter_versioned_sidebars/version-7.x.x-sidebars.json deleted file mode 100644 index 3e72540859..0000000000 --- a/docusaurus/flutter_versioned_sidebars/version-7.x.x-sidebars.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version-7.x.x/defaultSidebar": [ - { - "type": "autogenerated", - "dirName": "." - } - ] -} \ No newline at end of file diff --git a/docusaurus/flutter_versions.json b/docusaurus/flutter_versions.json deleted file mode 100644 index 643504ff34..0000000000 --- a/docusaurus/flutter_versions.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - "3.x.x", - "4.x.x", - "5.x.x", - "7.x.x" -] diff --git a/docusaurus/sidebars-flutter.json b/docusaurus/sidebars-flutter.json deleted file mode 100644 index 6a1c402391..0000000000 --- a/docusaurus/sidebars-flutter.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "docs": [ - { - "Basics": [ - "basics/installation", - "basics/introduction" - ] - }, - { - "UI Components": [ - "stream_chat_flutter/introduction", - "stream_chat_flutter/stream_chat_and_theming", - { - "Channel List": [ - "stream_chat_flutter/channel_list/stream_channel_list_view", - "stream_chat_flutter/channel_list/stream_channel_list_header", - "stream_chat_flutter/channel_list/stream_channel_grid_view", - "stream_chat_flutter/custom_widgets/slidable_channel_list_preview" - ] - }, - "stream_chat_flutter/stream_channel_header", - { - "Message List": [ - "stream_chat_flutter/message_list/stream_message_list_view", - "stream_chat_flutter/custom_widgets/customize_text_messages", - "stream_chat_flutter/message_list/stream_message_widget", - "stream_chat_flutter/message_list/stream_message_search_list_view", - "stream_chat_flutter/message_list/stream_message_search_grid_view", - "stream_chat_flutter/custom_widgets/customize_message_widget" - ] - }, - { - "Message Composer": [ - "stream_chat_flutter/message_composer/stream_message_input", - "stream_chat_flutter/custom_widgets/customize_message_actions", - "stream_chat_flutter/custom_widgets/autocomplete_triggers", - "stream_chat_flutter/custom_widgets/adding_custom_attachments", - "stream_chat_flutter/custom_widgets/customize_attachment_picker_modal" - ] - }, - { - "Member List": [ - "stream_chat_flutter/member_list/stream_member_list_view", - "stream_chat_flutter/member_list/stream_member_grid_view" - ] - }, - { - "User List": [ - "stream_chat_flutter/user_list/stream_user_list_view", - "stream_chat_flutter/user_list/stream_user_grid_view" - ] - } - ] - }, - { - "State & Offline": [ - "stream_chat_flutter_core/introduction", - "stream_chat_flutter_core/setup", - "stream_chat_flutter_core/stream_chat_core", - "stream_chat_flutter_core/stream_channel_list_controller", - "stream_chat_flutter_core/stream_channel_list_event_handler", - "stream_chat_flutter_core/message_list_core", - "stream_chat_flutter_core/stream_message_input_controller", - "stream_chat_flutter_core/stream_message_search_list_controller", - "stream_chat_flutter_core/stream_member_list_controller", - "stream_chat_flutter_core/stream_user_list_controller", - "stream_chat_flutter_core/lazy_load_scroll_view", - "stream_chat_flutter_core/paged_value_listenable_builder", - "guides/adding_local_data_persistence" - ] - }, - { - "Advanced Guides": [ - "guides/understanding_filters", - "guides/token_generation_with_firebase", - "guides/adding_localization", - { - "Push Notifications": [ - "guides/push-notifications/adding_push_notifications_v2", - "guides/push-notifications/adding_push_notifications" - ] - }, - "guides/end_to_end_chat_encryption", - "guides/error_reporting_with_sentry", - "guides/adding_chat_to_video_livestreams", - "guides/initialize_stream_chat_widget_tree" - ] - }, - { - "Migration Guides": [ - "guides/migrations/migration_guide_4_0", - "guides/migrations/migration_guide_5_0", - "guides/migrations/migration_guide_7_0", - "guides/migrations/migration_guide_8_0" - ] - } - ] - } \ No newline at end of file