rename package folders
@@ -1,65 +0,0 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
.packages
|
||||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
coverage/
|
||||
coverage_helper_test.dart
|
||||
|
||||
# Web related
|
||||
lib/generated_plugin_registrant.dart
|
||||
|
||||
# Exceptions to above rules.
|
||||
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||
# See https://www.dartlang.org/guides/libraries/private-files
|
||||
|
||||
# Files and directories created by pub
|
||||
.dart_tool/
|
||||
.packages
|
||||
build/
|
||||
# If you're building an application, you may want to check-in your pubspec.lock
|
||||
pubspec.lock
|
||||
|
||||
# Directory created by dartdoc
|
||||
# If you don't generate documentation locally you can remove this line.
|
||||
doc/api/
|
||||
|
||||
# Avoid committing generated Javascript files:
|
||||
*.dart.js
|
||||
*.info.json # Produced by the --dump-info flag.
|
||||
*.js # When generated by dart2js. Don't specify *.js if your
|
||||
# project includes source files written in JavaScript.
|
||||
*.js_
|
||||
*.js.deps
|
||||
*.js.map
|
||||
|
||||
fvm
|
||||
google-services.json
|
||||
example/ios/dist
|
||||
.vscode/
|
||||
@@ -1,406 +0,0 @@
|
||||
## 1.0.0-rc
|
||||
|
||||
- Integrated new-ui, split package functionality,
|
||||
|
||||
## 0.2.20+2
|
||||
|
||||
- Added `shouldAddChannel` to ChannelsBloc in order to check if a channel has to be added to the list when a new message arrives
|
||||
|
||||
## 0.2.20+1
|
||||
|
||||
- Fixed bug that caused video attachment to show the same preview
|
||||
|
||||
## 0.2.20
|
||||
|
||||
- Implement shadowban
|
||||
|
||||
## 0.2.19
|
||||
|
||||
- Updated llc dependency
|
||||
- Added loading builder in channellistview
|
||||
- Added sendButtonLocation and animationduration to messageinput
|
||||
|
||||
## 0.2.18
|
||||
|
||||
- Updated llc dependency
|
||||
|
||||
## 0.2.17+2
|
||||
|
||||
- Expose ChannelsBloc.channelsComparator to sort channels on message.new event
|
||||
|
||||
## 0.2.17+1
|
||||
|
||||
- Fix mention tap bug
|
||||
|
||||
## 0.2.17
|
||||
|
||||
- Expose messageInputDecoration as part of the theme
|
||||
|
||||
## 0.2.16
|
||||
|
||||
- Do not wrap channel preview builder. Users will have to implement they're custom onTap/onLongPress implementation
|
||||
- Make public autofocus field of the TextField of message_input
|
||||
|
||||
## 0.2.15
|
||||
|
||||
- Add onLongPress on channel when using custom channel builder
|
||||
|
||||
## 0.2.14
|
||||
|
||||
- Add onMessageTap callbacks
|
||||
|
||||
## 0.2.13+2
|
||||
|
||||
- Add debounce to on change messageinput listener
|
||||
|
||||
## 0.2.13+1
|
||||
|
||||
- Use TextEditingController.addListener instead of TextField.onChanged
|
||||
|
||||
## 0.2.13
|
||||
|
||||
- Update llc dependency
|
||||
- Send parent_id in typing events
|
||||
- Expose addition input styling options
|
||||
- Expose builder for empty channel state
|
||||
|
||||
## 0.2.12
|
||||
|
||||
- Upgrade dependencies
|
||||
- Check if user.extraData['image'] is not null before using it
|
||||
|
||||
## 0.2.11+1
|
||||
|
||||
- Fix error with channel query while handling background notifications
|
||||
|
||||
## 0.2.11
|
||||
|
||||
- Update llc dependency
|
||||
- Update widget to use `channel.state.unreadCountStream`
|
||||
|
||||
## 0.2.10
|
||||
|
||||
- Update llc dependency
|
||||
- Add `separatorBuilder` to `ChannelListView`
|
||||
|
||||
## 0.2.9+1
|
||||
|
||||
- Update llc dependency
|
||||
- Minor bug fixes
|
||||
|
||||
## 0.2.9
|
||||
|
||||
- Update llc dependency
|
||||
- Fix example to run on Flutter web
|
||||
|
||||
## 0.2.8+4
|
||||
|
||||
- fix: Auto capitalize the start of sentences in MessageInput
|
||||
- Update dependencies
|
||||
|
||||
## 0.2.8+3
|
||||
|
||||
- Add simple example of channel creation in sample app
|
||||
- Add back button to the full-screen video view
|
||||
- Update llc version
|
||||
|
||||
## 0.2.8+2
|
||||
|
||||
- Add back button to the full-screen view
|
||||
|
||||
## 0.2.8+1
|
||||
|
||||
- Update LLC dependency
|
||||
- Update file_picker dependency
|
||||
|
||||
## 0.2.8
|
||||
|
||||
- Update LLC dependency
|
||||
|
||||
## 0.2.7+2
|
||||
|
||||
- Fix channellistview loading when client is not initialized
|
||||
- Update LLC dependency
|
||||
|
||||
## 0.2.7
|
||||
|
||||
- Update llc dependency
|
||||
- Fixed a bug that made the SDK crash if it went to background while not connected
|
||||
|
||||
## 0.2.6+1
|
||||
|
||||
- Update llc dependency
|
||||
|
||||
## 0.2.6
|
||||
|
||||
- Add `pullToRefresh` property to `ChannelListView`
|
||||
- Add `onLinkTap` to `MessageWidget`
|
||||
|
||||
## 0.2.5
|
||||
|
||||
- Implement `didUpdateWidget` in `ChannelListView` to react to setState
|
||||
|
||||
## 0.2.4
|
||||
|
||||
- Update llc dependency
|
||||
|
||||
## 0.2.3
|
||||
|
||||
- Add `lockChannelsOrder` parameter to `ChannelsBloc`
|
||||
|
||||
## 0.2.2+3
|
||||
|
||||
- Fix `ChannelListView` channel hidden behaviour
|
||||
|
||||
- Refresh `ChannelListView` on new message from hidden channel
|
||||
|
||||
## 0.2.2+1
|
||||
|
||||
- Fix some components to implement a splitview example
|
||||
|
||||
## 0.2.2
|
||||
|
||||
- Add `messageLinks` property to `MessageTheme` to customize links color
|
||||
|
||||
## 0.2.1+2
|
||||
|
||||
- Update llc dependency
|
||||
|
||||
## 0.2.1+1
|
||||
|
||||
- Update llc dependency
|
||||
|
||||
## 0.2.1
|
||||
|
||||
- Better ui components
|
||||
- Add read indicators
|
||||
- Add system messages
|
||||
- Use llc 0.2
|
||||
- Add `ChannelsBloc` widget to manage a list of channels with pagination
|
||||
|
||||
## 0.2.1-alpha+11
|
||||
|
||||
- Update llc dependency
|
||||
|
||||
## 0.2.1-alpha+10
|
||||
|
||||
- Update llc dependency
|
||||
|
||||
## 0.2.1-alpha+9
|
||||
|
||||
- Add read indicators
|
||||
- Update llc dependency
|
||||
|
||||
## 0.2.1-alpha+8
|
||||
|
||||
- User queryMembers for mentions
|
||||
|
||||
## 0.2.1-alpha+7
|
||||
|
||||
- Update llc dependency
|
||||
|
||||
## 0.2.1-alpha+6
|
||||
|
||||
- Update llc dependency
|
||||
- Minor bugfix
|
||||
|
||||
## 0.2.1-alpha+4
|
||||
|
||||
- Update llc dependency
|
||||
|
||||
- Add system messages
|
||||
|
||||
## 0.2.1-alpha+3
|
||||
|
||||
- Update llc dependency
|
||||
|
||||
- Fix hero tag generation for attachment
|
||||
|
||||
## 0.2.1-alpha+2
|
||||
|
||||
- Fixed reactions bubble going below other messages
|
||||
- Updated llc dependency
|
||||
|
||||
## 0.2.1-alpha+1
|
||||
|
||||
- Removed the additional `Navigator` in `StreamChat` widget.
|
||||
It was added to make the app have the `StreamChat` widget as ancestor in every route.
|
||||
Now the recommended way to add `StreamChat` to your app is using the `builder` property of your `MaterialApp` widget.
|
||||
Otherwise you can use it in the usual way, but you need to add a `StreamChat` widget to every route of your app.
|
||||
Read [this issue](https://github.com/GetStream/stream-chat-flutter/issues/47) for more information.
|
||||
|
||||
```dart
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
theme: ThemeData.light(),
|
||||
darkTheme: ThemeData.dark(),
|
||||
themeMode: ThemeMode.system,
|
||||
builder: (context, widget) {
|
||||
return StreamChat(
|
||||
child: widget,
|
||||
client: client,
|
||||
);
|
||||
},
|
||||
home: ChannelListPage(),
|
||||
);
|
||||
```
|
||||
|
||||
- Fix reaction bubble going below previous message on iOS
|
||||
|
||||
- Fix message list view reloading messages even if the pagination is ended
|
||||
|
||||
## 0.2.1-alpha
|
||||
|
||||
- New message widget
|
||||
- Moved some properties from `MessageListView` to `MessageWidget`
|
||||
- Added `MessageDetails` property to `MessageBuilder`
|
||||
- Added example to customize the message using `MessageWidget` (`customize_message_widget.dart`)
|
||||
|
||||
## 0.2.0-alpha+15
|
||||
|
||||
- Add background color in StreamChatTheme
|
||||
|
||||
## 0.2.0-alpha+13
|
||||
|
||||
- Handle channel deleted event
|
||||
|
||||
## 0.2.0-alpha+11
|
||||
|
||||
- Fix message builder and add messageList to it
|
||||
|
||||
## 0.2.0-alpha+10
|
||||
|
||||
- Add date divider builder
|
||||
|
||||
- Fix reply indicator tap
|
||||
|
||||
## 0.2.0-alpha+9
|
||||
|
||||
- Add `attachmentBuilders` to `MessageWidget` and `MessageListView`
|
||||
|
||||
## 0.2.0-alpha+7
|
||||
|
||||
- Update llc dependency
|
||||
|
||||
## 0.2.0-alpha+5
|
||||
|
||||
- Remove dependencies on notification service
|
||||
|
||||
- Expose some helping method for integrate offline storage with push notifications
|
||||
|
||||
## 0.2.0-alpha+3
|
||||
|
||||
- Fix overflow in mentions overlay
|
||||
|
||||
## 0.2.0-alpha+2
|
||||
|
||||
- Add better mime detection
|
||||
|
||||
## 0.2.0-alpha+1
|
||||
|
||||
- Fix video loading and error
|
||||
|
||||
## 0.2.0-alpha
|
||||
|
||||
- Offline storage
|
||||
|
||||
- Push notifications
|
||||
|
||||
- Minor bug fixes
|
||||
|
||||
## 0.1.20s
|
||||
|
||||
- Add message configuration properties to MessageListView
|
||||
|
||||
## 0.1.19
|
||||
|
||||
- Fix video aspect ratio
|
||||
|
||||
- Add property to decide whether to enable video fullscreen
|
||||
|
||||
- Add property to hide the attachment button
|
||||
|
||||
- Do not show send button if an attachment is still uploading
|
||||
|
||||
- Unfocus and disable the TextField before opening the camera (workaround for flutter/flutter#42417)
|
||||
|
||||
- Add gesture (vertical drag down) to close the keyboard
|
||||
|
||||
- Add keyboard type parameters (set it to TextInputType.text to show the submit button that will even close the keyboard)
|
||||
|
||||
The property showVideoFullScreen was added mainly because of this issue brianegan/chewie#261
|
||||
|
||||
## 0.1.18
|
||||
|
||||
- Add message list date separators
|
||||
|
||||
## 0.1.17
|
||||
|
||||
- Add dark theme
|
||||
|
||||
## 0.1.16
|
||||
|
||||
- Add possibility to show the other users username next to the message timestamp
|
||||
|
||||
## 0.1.15
|
||||
|
||||
- Fix MessageInput overflow
|
||||
|
||||
## 0.1.14
|
||||
|
||||
- Add automatic keep alive to streamchat
|
||||
|
||||
## 0.1.12
|
||||
|
||||
- Fix dependency error on iOS using flutter_form_builder
|
||||
|
||||
## 0.1.11
|
||||
|
||||
- Fix bug in ChannelPreview when list of messages is empty
|
||||
|
||||
## 0.1.10
|
||||
|
||||
- Do not automatically dispose Client object when disposing StreamChat widget
|
||||
|
||||
## 0.1.9
|
||||
|
||||
- Fix message ui overflow
|
||||
|
||||
## 0.1.8
|
||||
|
||||
- Bug fix
|
||||
|
||||
## 0.1.7
|
||||
|
||||
- Add chat commands
|
||||
|
||||
- Add edit message
|
||||
|
||||
## 0.1.6+4
|
||||
|
||||
- Add some documentation
|
||||
|
||||
## 0.1.5
|
||||
|
||||
- Fix channels pagination
|
||||
|
||||
## 0.1.4
|
||||
|
||||
- Fix message widget builder on reaction
|
||||
|
||||
## 0.1.3
|
||||
|
||||
- Fix upload attachment
|
||||
|
||||
## 0.1.2
|
||||
|
||||
- Fix avatar shape
|
||||
|
||||
## 0.1.1
|
||||
|
||||
- Add ThreadHeader
|
||||
|
||||
## 0.0.1
|
||||
|
||||
- First release
|
||||
@@ -1,219 +0,0 @@
|
||||
SOURCE CODE LICENSE AGREEMENT
|
||||
|
||||
IMPORTANT - READ THIS CAREFULLY BEFORE DOWNLOADING, INSTALLING, USING OR
|
||||
ELECTRONICALLY ACCESSING THIS PROPRIETARY PRODUCT.
|
||||
|
||||
THIS IS A LEGAL AGREEMENT BETWEEN STREAM.IO, INC. (“STREAM.IO”) AND THE
|
||||
BUSINESS ENTITY OR PERSON FOR WHOM YOU (“YOU”) ARE ACTING (“CUSTOMER”) AS THE
|
||||
LICENSEE OF THE PROPRIETARY SOFTWARE INTO WHICH THIS AGREEMENT HAS BEEN
|
||||
INCLUDED (THE “AGREEMENT”). YOU AGREE THAT YOU ARE THE CUSTOMER, OR YOU ARE AN
|
||||
EMPLOYEE OR AGENT OF CUSTOMER AND ARE ENTERING INTO THIS AGREEMENT FOR LICENSE
|
||||
OF THE SOFTWARE BY CUSTOMER FOR CUSTOMER’S BUSINESS PURPOSES AS DESCRIBED IN
|
||||
AND IN ACCORDANCE WITH THIS AGREEMENT. YOU HEREBY AGREE THAT YOU ENTER INTO
|
||||
THIS AGREEMENT ON BEHALF OF CUSTOMER AND THAT YOU HAVE THE AUTHORITY TO BIND
|
||||
CUSTOMER TO THIS AGREEMENT.
|
||||
|
||||
STREAM.IO IS WILLING TO LICENSE THE SOFTWARE TO CUSTOMER ONLY ON THE FOLLOWING
|
||||
CONDITIONS: (1) YOU ARE A CURRENT CUSTOMER OF STREAM.IO; (2) YOU ARE NOT A
|
||||
COMPETITOR OF STREAM.IO; AND (3) THAT YOU ACCEPT ALL THE TERMS IN THIS
|
||||
AGREEMENT. BY DOWNLOADING, INSTALLING, CONFIGURING, ACCESSING OR OTHERWISE
|
||||
USING THE SOFTWARE, INCLUDING ANY UPDATES, UPGRADES, OR NEWER VERSIONS, YOU
|
||||
REPRESENT, WARRANT AND ACKNOWLEDGE THAT (A) CUSTOMER IS A CURRENT CUSTOMER OF
|
||||
STREAM.IO; (B) CUSTOMER IS NOT A COMPETITOR OF STREAM.IO; AND THAT (C) YOU HAVE
|
||||
READ THIS AGREEMENT, UNDERSTAND THIS AGREEMENT, AND THAT CUSTOMER AGREES TO BE
|
||||
BOUND BY ALL THE TERMS OF THIS AGREEMENT.
|
||||
|
||||
IF YOU DO NOT AGREE TO ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT,
|
||||
STREAM.IO IS UNWILLING TO LICENSE THE SOFTWARE TO CUSTOMER, AND THEREFORE, DO
|
||||
NOT COMPLETE THE DOWNLOAD PROCESS, ACCESS OR OTHERWISE USE THE SOFTWARE, AND
|
||||
CUSTOMER SHOULD IMMEDIATELY RETURN THE SOFTWARE AND CEASE ANY USE OF THE
|
||||
SOFTWARE.
|
||||
|
||||
1. SOFTWARE. The Stream.io software accompanying this Agreement, may include
|
||||
Source Code, Executable Object Code, associated media, printed materials and
|
||||
documentation (collectively, the “Software”). The Software also includes any
|
||||
updates or upgrades to or new versions of the original Software, if and when
|
||||
made available to you by Stream.io. “Source Code” means computer programming
|
||||
code in human readable form that is not suitable for machine execution without
|
||||
the intervening steps of interpretation or compilation. “Executable Object
|
||||
Code" means the computer programming code in any other form than Source Code
|
||||
that is not readily perceivable by humans and suitable for machine execution
|
||||
without the intervening steps of interpretation or compilation. “Site” means a
|
||||
Customer location controlled by Customer. “Authorized User” means any employee
|
||||
or contractor of Customer working at the Site, who has signed a written
|
||||
confidentiality agreement with Customer or is otherwise bound in writing by
|
||||
confidentiality and use obligations at least as restrictive as those imposed
|
||||
under this Agreement.
|
||||
|
||||
2. LICENSE GRANT. Subject to the terms and conditions of this Agreement, in
|
||||
consideration for the representations, warranties, and covenants made by
|
||||
Customer in this Agreement, Stream.io grants to Customer, during the term of
|
||||
this Agreement, a personal, non-exclusive, non-transferable, non-sublicensable
|
||||
license to:
|
||||
|
||||
a. install and use Software Source Code on password protected computers at a Site,
|
||||
restricted to Authorized Users;
|
||||
|
||||
b. create derivative works, improvements (whether or not patentable), extensions
|
||||
and other modifications to the Software Source Code (“Modifications”) to build
|
||||
unique scalable newsfeeds, activity streams, and in-app messaging via Stream’s
|
||||
application program interface (“API”);
|
||||
|
||||
c. compile the Software Source Code to create Executable Object Code versions of
|
||||
the Software Source Code and Modifications to build such newsfeeds, activity
|
||||
streams, and in-app messaging via the API;
|
||||
|
||||
d. install, execute and use such Executable Object Code versions solely for
|
||||
Customer’s internal business use (including development of websites through
|
||||
which data generated by Stream services will be streamed (“Apps”));
|
||||
|
||||
e. use and distribute such Executable Object Code as part of Customer’s Apps; and
|
||||
|
||||
f. make electronic copies of the Software and Modifications as required for backup
|
||||
or archival purposes.
|
||||
|
||||
3. RESTRICTIONS. Customer is responsible for all activities that occur in
|
||||
connection with the Software. Customer will not, and will not attempt to: (a)
|
||||
sublicense or transfer the Software or any Source Code related to the Software
|
||||
or any of Customer’s rights under this Agreement, except as otherwise provided
|
||||
in this Agreement, (b) use the Software Source Code for the benefit of a third
|
||||
party or to operate a service; (c) allow any third party to access or use the
|
||||
Software Source Code; (d) sublicense or distribute the Software Source Code or
|
||||
any Modifications in Source Code or other derivative works based on any part of
|
||||
the Software Source Code; (e) use the Software in any manner that competes with
|
||||
Stream.io or its business; or (e) otherwise use the Software in any manner that
|
||||
exceeds the scope of use permitted in this Agreement. Customer shall use the
|
||||
Software in compliance with any accompanying documentation any laws applicable
|
||||
to Customer.
|
||||
|
||||
4. OPEN SOURCE. Customer and its Authorized Users shall not use any software or
|
||||
software components that are open source in conjunction with the Software
|
||||
Source Code or any Modifications in Source Code or in any way that could
|
||||
subject the Software to any open source licenses.
|
||||
|
||||
5. CONTRACTORS. Under the rights granted to Customer under this Agreement,
|
||||
Customer may permit its employees, contractors, and agencies of Customer to
|
||||
become Authorized Users to exercise the rights to the Software granted to
|
||||
Customer in accordance with this Agreement solely on behalf of Customer to
|
||||
provide services to Customer; provided that Customer shall be liable for the
|
||||
acts and omissions of all Authorized Users to the extent any of such acts or
|
||||
omissions, if performed by Customer, would constitute a breach of, or otherwise
|
||||
give rise to liability to Customer under, this Agreement. Customer shall not
|
||||
and shall not permit any Authorized User to use the Software except as
|
||||
expressly permitted in this Agreement.
|
||||
|
||||
6. COMPETITIVE PRODUCT DEVELOPMENT. Customer shall not use the Software in any way
|
||||
to engage in the development of products or services which could be reasonably
|
||||
construed to provide a complete or partial functional or commercial alternative
|
||||
to Stream.io’s products or services (a “Competitive Product”). Customer shall
|
||||
ensure that there is no direct or indirect use of, or sharing of, Software
|
||||
source code, or other information based upon or derived from the Software to
|
||||
develop such products or services. Without derogating from the generality of
|
||||
the foregoing, development of Competitive Products shall include having direct
|
||||
or indirect access to, supervising, consulting or assisting in the development
|
||||
of, or producing any specifications, documentation, object code or source code
|
||||
for, all or part of a Competitive Product.
|
||||
|
||||
7. LIMITATION ON MODIFICATIONS. Notwithstanding any provision in this Agreement,
|
||||
Modifications may only be created and used by Customer as permitted by this
|
||||
Agreement and Modification Source Code may not be distributed to third parties.
|
||||
Customer will not assert against Stream.io, its affiliates, or their customers,
|
||||
direct or indirect, agents and contractors, in any way, any patent rights that
|
||||
Customer may obtain relating to any Modifications for Stream.io, its
|
||||
affiliates’, or their customers’, direct or indirect, agents’ and contractors’
|
||||
manufacture, use, import, offer for sale or sale of any Stream.io products or
|
||||
services.
|
||||
|
||||
8. DELIVERY AND ACCEPTANCE. The Software will be delivered electronically pursuant
|
||||
to Stream.io standard download procedures. The Software is deemed accepted upon
|
||||
delivery.
|
||||
|
||||
9. IMPLEMENTATION AND SUPPORT. Stream.io has no obligation under this Agreement to
|
||||
provide any support or consultation concerning the Software.
|
||||
|
||||
10. TERM AND TERMINATION. The term of this Agreement begins when the Software is
|
||||
downloaded or accessed and shall continue until terminated. Either party may
|
||||
terminate this Agreement upon written notice. This Agreement shall
|
||||
automatically terminate if Customer is or becomes a competitor of Stream.io or
|
||||
makes or sells any Competitive Products. Upon termination of this Agreement for
|
||||
any reason, (a) all rights granted to Customer in this Agreement immediately
|
||||
cease to exist, (b) Customer must promptly discontinue all use of the Software
|
||||
and return to Stream.io or destroy all copies of the Software in Customer’s
|
||||
possession or control. Any continued use of the Software by Customer or attempt
|
||||
by Customer to exercise any rights under this Agreement after this Agreement
|
||||
has terminated shall be considered copyright infringement and subject Customer
|
||||
to applicable remedies for copyright infringement. Sections 2, 5, 6, 8 and 9
|
||||
shall survive expiration or termination of this Agreement for any reason.
|
||||
|
||||
11. OWNERSHIP. As between the parties, the Software and all worldwide intellectual
|
||||
property rights and proprietary rights relating thereto or embodied therein,
|
||||
are the exclusive property of Stream.io and its suppliers. Stream.io and its
|
||||
suppliers reserve all rights in and to the Software not expressly granted to
|
||||
Customer in this Agreement, and no other licenses or rights are granted by
|
||||
implication, estoppel or otherwise.
|
||||
|
||||
12. WARRANTY DISCLAIMER. USE OF THIS SOFTWARE IS ENTIRELY AT YOURS AND CUSTOMER’S
|
||||
OWN RISK. THE SOFTWARE IS PROVIDED “AS IS” WITHOUT ANY WARRANTY OF ANY KIND
|
||||
WHATSOEVER. STREAM.IO DOES NOT MAKE, AND HEREBY DISCLAIMS, ANY WARRANTY OF ANY
|
||||
KIND, WHETHER EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING WITHOUT
|
||||
LIMITATION, THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, TITLE, NON-INFRINGEMENT OF THIRD-PARTY RIGHTS, RESULTS, EFFORTS,
|
||||
QUALITY OR QUIET ENJOYMENT. STREAM.IO DOES NOT WARRANT THAT THE SOFTWARE IS
|
||||
ERROR-FREE, WILL FUNCTION WITHOUT INTERRUPTION, WILL MEET ANY SPECIFIC NEED
|
||||
THAT CUSTOMER HAS, THAT ALL DEFECTS WILL BE CORRECTED OR THAT IT IS
|
||||
SUFFICIENTLY DOCUMENTED TO BE USABLE BY CUSTOMER. TO THE EXTENT THAT STREAM.IO
|
||||
MAY NOT DISCLAIM ANY WARRANTY AS A MATTER OF APPLICABLE LAW, THE SCOPE AND
|
||||
DURATION OF SUCH WARRANTY WILL BE THE MINIMUM PERMITTED UNDER SUCH LAW.
|
||||
CUSTOMER ACKNOWLEDGES THAT IT HAS RELIED ON NO WARRANTIES OTHER THAN THE
|
||||
EXPRESS WARRANTIES IN THIS AGREEMENT.
|
||||
|
||||
13. LIMITATION OF LIABILITY. TO THE FULLEST EXTENT PERMISSIBLE BY LAW, STREAM.IO’S
|
||||
TOTAL LIABILITY FOR ALL DAMAGES ARISING OUT OF OR RELATED TO THE SOFTWARE OR
|
||||
THIS AGREEMENT, WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE,
|
||||
SHALL NOT EXCEED $100. IN NO EVENT WILL STREAM.IO BE LIABLE FOR ANY INDIRECT,
|
||||
CONSEQUENTIAL, EXEMPLARY, PUNITIVE, SPECIAL OR INCIDENTAL DAMAGES OF ANY KIND
|
||||
WHATSOEVER, INCLUDING ANY LOST DATA AND LOST PROFITS, ARISING FROM OR RELATING
|
||||
TO THE SOFTWARE EVEN IF STREAM.IO HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES. CUSTOMER ACKNOWLEDGES THAT THIS PROVISION REFLECTS THE AGREED UPON
|
||||
ALLOCATION OF RISK FOR THIS AGREEMENT AND THAT STREAM.IO WOULD NOT ENTER INTO
|
||||
THIS AGREEMENT WITHOUT THESE LIMITATIONS ON ITS LIABILITY.
|
||||
|
||||
14. General. Customer may not assign or transfer this Agreement, by operation of
|
||||
law or otherwise, or any of its rights under this Agreement (including the
|
||||
license rights granted to Customer) to any third party without Stream.io’s
|
||||
prior written consent, which consent will not be unreasonably withheld or
|
||||
delayed. Stream.io may assign this Agreement, without consent, including, but
|
||||
limited to, affiliate or any successor to all or substantially all its business
|
||||
or assets to which this Agreement relates, whether by merger, sale of assets,
|
||||
sale of stock, reorganization or otherwise. Any attempted assignment or
|
||||
transfer in violation of the foregoing will be null and void. Stream.io shall
|
||||
not be liable hereunder by reason of any failure or delay in the performance of
|
||||
its obligations hereunder for any cause which is beyond the reasonable control.
|
||||
All notices, consents, and approvals under this Agreement must be delivered in
|
||||
writing by courier, by electronic mail, or by certified or registered mail,
|
||||
(postage prepaid and return receipt requested) to the other party at the
|
||||
address set forth in the customer agreement between Stream.io and Customer and
|
||||
will be effective upon receipt or when delivery is refused. This Agreement will
|
||||
be governed by and interpreted in accordance with the laws of the State of
|
||||
Colorado, without reference to its choice of laws rules. The United Nations
|
||||
Convention on Contracts for the International Sale of Goods does not apply to
|
||||
this Agreement. Any action or proceeding arising from or relating to this
|
||||
Agreement shall be brought in a federal or state court in Denver, Colorado, and
|
||||
each party irrevocably submits to the jurisdiction and venue of any such court
|
||||
in any such action or proceeding. All waivers must be in writing. Any waiver or
|
||||
failure to enforce any provision of this Agreement on one occasion will not be
|
||||
deemed a waiver of any other provision or of such provision on any other
|
||||
occasion. If any provision of this Agreement is unenforceable, such provision
|
||||
will be changed and interpreted to accomplish the objectives of such provision
|
||||
to the greatest extent possible under applicable law and the remaining
|
||||
provisions will continue in full force and effect. Customer shall not violate
|
||||
any applicable law, rule or regulation, including those regarding the export of
|
||||
technical data. The headings of Sections of this Agreement are for convenience
|
||||
and are not to be used in interpreting this Agreement. As used in this
|
||||
Agreement, the word “including” means “including but not limited to.” This
|
||||
Agreement (including all exhibits and attachments) constitutes the entire
|
||||
agreement between the parties regarding the subject hereof and supersedes all
|
||||
prior or contemporaneous agreements, understandings and communication, whether
|
||||
written or oral. This Agreement may be amended only by a written document
|
||||
signed by both parties. The terms of any purchase order or similar document
|
||||
submitted by Customer to Stream.io will have no effect.
|
||||
@@ -1,165 +0,0 @@
|
||||
# Official Flutter SDK for [Stream Chat](https://getstream.io/chat/)
|
||||
|
||||
<p align="center">
|
||||
<a href="https://getstream.io/chat/flutter/tutorial/"><img src="https://i.imgur.com/L4Mj8S2.png" alt="Flutter Chat" width="60%" /></a>
|
||||
</p>
|
||||
|
||||
> The official Flutter components for Stream Chat, a service for
|
||||
> building chat applications.
|
||||
|
||||
[](https://pub.dartlang.org/packages/stream_chat_flutter)
|
||||

|
||||
[](https://gitter.im/GetStream/stream-chat-flutter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||

|
||||
<img align="right" src="https://getstream.imgix.net/images/ios-chat-tutorial/iphone_chat_art@1x.png?auto=format,enhance" width="50%" />
|
||||
|
||||
**Quick Links**
|
||||
|
||||
- [Register](https://getstream.io/chat/trial/) to get an API key for Stream Chat
|
||||
- [Flutter Chat Tutorial](https://getstream.io/chat/flutter/tutorial/)
|
||||
- [Chat UI Kit](https://getstream.io/chat/ui-kit/)
|
||||
|
||||
## Flutter Chat Tutorial
|
||||
|
||||
The best place to start is the [Flutter Chat Tutorial](https://getstream.io/chat/flutter/tutorial/).
|
||||
It teaches you how to use this SDK and also shows how to make frequently required changes.
|
||||
|
||||
## Example App
|
||||
|
||||
This repo includes a fully functional example app with setup instructions.
|
||||
The example is available under the [example](https://github.com/GetStream/stream-chat-flutter/tree/master/example) folder.
|
||||
|
||||
## Add dependency
|
||||
Add this to your package's pubspec.yaml file, use the latest version [](https://pub.dartlang.org/packages/stream_chat_flutter)
|
||||
```yaml
|
||||
dependencies:
|
||||
stream_chat_flutter: ^latest_version
|
||||
```
|
||||
|
||||
You should then run `flutter packages get`
|
||||
|
||||
### Android
|
||||
|
||||
All set ✅
|
||||
|
||||
### 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.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
It may happen that you have some problems building the app.
|
||||
If it seems related to the [flutter file picker plugin](https://github.com/miguelpruivo/flutter_file_picker) make sure to check [this page](https://github.com/miguelpruivo/flutter_file_picker/wiki/Troubleshooting)
|
||||
|
||||
## Docs
|
||||
|
||||
This package provides UI components required for integrating Stream Chat into your application.
|
||||
Alternatively, you may use the core package (stream_chat_flutter_core) which allows more customisation and provides business logic but no UI components.
|
||||
If you require the maximum amount of control over the API, please use the low level client package: stream_chat.
|
||||
|
||||
### UI Components
|
||||
|
||||
These are the available Widgets that you can use to build your application UI.
|
||||
Every widget uses the `StreamChat` or `StreamChannel` widgets to manage the state and communicate with Stream services.
|
||||
|
||||
- [ChannelHeader](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/ChannelHeader-class.html)
|
||||
- [ChannelImage](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/ChannelImage-class.html)
|
||||
- [ChannelListView](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/ChannelListView-class.html)
|
||||
- [ChannelName](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/ChannelName-class.html)
|
||||
- [ChannelPreview](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/ChannelPreview-class.html)
|
||||
- [MessageInput](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/MessageInput-class.html)
|
||||
- [MessageListView](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/MessageListView-class.html)
|
||||
- [MessageWidget](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/MessageWidget-class.html)
|
||||
- [StreamChatTheme](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChatTheme-class.html)
|
||||
- [ThreadHeader](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/ThreadHeader-class.html)
|
||||
- ...
|
||||
|
||||
### Customizing styles
|
||||
|
||||
The Flutter SDK comes with a fully designed set of widgets that you can customize to fit with your application style and typography.
|
||||
Changing the theme of Chat widgets works in a very similar way that `MaterialApp` and `Theme` do.
|
||||
|
||||
Out of the box, all chat widgets use their default styling, and there are two ways to change the styling:
|
||||
|
||||
1. Initialize the `StreamChatTheme` from your existing `MaterialApp` style
|
||||
```dart
|
||||
class MyApp extends StatelessWidget {
|
||||
final StreamChatClient client;
|
||||
|
||||
MyApp(this.client);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = ThemeData(
|
||||
primarySwatch: Colors.green,
|
||||
);
|
||||
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
builder: (context, child) => StreamChat(
|
||||
child: child,
|
||||
client: client,
|
||||
streamChatThemeData: StreamChatThemeData.fromTheme(theme),
|
||||
),
|
||||
home: ChannelListPage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Construct a custom theme and provide all the customizations needed
|
||||
```dart
|
||||
class MyApp extends StatelessWidget {
|
||||
final StreamChatClient client;
|
||||
|
||||
MyApp(this.client);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = ThemeData(
|
||||
primarySwatch: Colors.green,
|
||||
);
|
||||
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
builder: (context, child) => StreamChat(
|
||||
child: child,
|
||||
client: client,
|
||||
streamChatThemeData: StreamChatThemeData.fromTheme(theme).copyWith(
|
||||
ownMessageTheme: MessageTheme(
|
||||
messageBackgroundColor: Colors.black,
|
||||
messageText: TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
avatarTheme: AvatarTheme(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
home: ChannelListPage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Offline storage
|
||||
|
||||
By default the library saves information about channels and messages in a SQLite DB.
|
||||
|
||||
Set the property `persistenceEnabled` to false if you don't want to use the offline storage.
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome code changes that improve this library or fix a problem,
|
||||
please make sure to follow all best practices and add tests if applicable before submitting a Pull Request on Github.
|
||||
We are pleased to merge your code into the official repository.
|
||||
Make sure to sign our [Contributor License Agreement (CLA)](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) first.
|
||||
See our license file for more details.
|
||||
@@ -1,63 +0,0 @@
|
||||
#include: package:pedantic/analysis_options.yaml
|
||||
#
|
||||
#analyzer:
|
||||
# enable-experiment:
|
||||
# - extension-methods
|
||||
# exclude:
|
||||
# - lib/**/*.g.dart
|
||||
# - example/**
|
||||
#
|
||||
#linter:
|
||||
# rules:
|
||||
# # these rules are documented on and in the same order as
|
||||
# # the Dart Lint rules page to make maintenance easier
|
||||
# # https://github.com/dart-lang/linter/blob/master/example/all.yaml
|
||||
# # - always_declare_return_types
|
||||
# # - always_specify_types
|
||||
# # - annotate_overrides
|
||||
# # - avoid_as
|
||||
# - avoid_empty_else
|
||||
# - avoid_init_to_null
|
||||
# - avoid_return_types_on_setters
|
||||
# - avoid_web_libraries_in_flutter
|
||||
# - await_only_futures
|
||||
# - camel_case_types
|
||||
# - cancel_subscriptions
|
||||
# - close_sinks
|
||||
# # - comment_references # we do not presume as to what people want to reference in their dartdocs
|
||||
# # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204
|
||||
# - control_flow_in_finally
|
||||
# - empty_constructor_bodies
|
||||
# - empty_statements
|
||||
# - hash_and_equals
|
||||
# - implementation_imports
|
||||
# # - invariant_booleans
|
||||
# # - iterable_contains_unrelated_type
|
||||
# - library_names
|
||||
# # - library_prefixes
|
||||
# # - list_remove_unrelated_type
|
||||
# # - literal_only_boolean_expressions
|
||||
# - non_constant_identifier_names
|
||||
# # - one_member_abstracts
|
||||
# # - only_throw_errors
|
||||
# # - overridden_fields
|
||||
## - package_api_docs
|
||||
# - package_names
|
||||
# - package_prefixed_library_names
|
||||
# - prefer_is_not_empty
|
||||
# # - prefer_mixin # https://github.com/dart-lang/language/issues/32
|
||||
# - public_member_api_docs
|
||||
# - slash_for_doc_comments
|
||||
# # - sort_constructors_first
|
||||
# # - sort_unnamed_constructors_first
|
||||
# # - super_goes_last # no longer needed w/ Dart 2
|
||||
# - test_types_in_equals
|
||||
# - throw_in_finally
|
||||
# # - type_annotate_public_apis # subset of always_specify_types
|
||||
# - type_init_formals
|
||||
# # - unawaited_futures
|
||||
# - unnecessary_brace_in_string_interps
|
||||
# - unnecessary_getters_setters
|
||||
# - unnecessary_statements
|
||||
- unrelated_type_equality_checks
|
||||
- valid_regexps
|
||||
@@ -1,39 +0,0 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
.packages
|
||||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
|
||||
# Web related
|
||||
lib/generated_plugin_registrant.dart
|
||||
|
||||
# Exceptions to above rules.
|
||||
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||
|
||||
fvm
|
||||
@@ -1,10 +0,0 @@
|
||||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: 0b8abb4724aa590dd0f429683339b1e045a1594d
|
||||
channel: stable
|
||||
|
||||
project_type: app
|
||||
@@ -1,7 +0,0 @@
|
||||
# Flutter Chat Example Application
|
||||
|
||||
An example chat application using Flutter and Stream Chat.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure to follow the steps from the [tutorial](https://getstream.io/chat/flutter/tutorial/).
|
||||
@@ -1,7 +0,0 @@
|
||||
gradle-wrapper.jar
|
||||
/.gradle
|
||||
/captures/
|
||||
/gradlew
|
||||
/gradlew.bat
|
||||
/local.properties
|
||||
GeneratedPluginRegistrant.java
|
||||
@@ -1,71 +0,0 @@
|
||||
def localProperties = new Properties()
|
||||
def localPropertiesFile = rootProject.file('local.properties')
|
||||
if (localPropertiesFile.exists()) {
|
||||
localPropertiesFile.withReader('UTF-8') { reader ->
|
||||
localProperties.load(reader)
|
||||
}
|
||||
}
|
||||
|
||||
def flutterRoot = localProperties.getProperty('flutter.sdk')
|
||||
if (flutterRoot == null) {
|
||||
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
|
||||
}
|
||||
|
||||
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
||||
if (flutterVersionCode == null) {
|
||||
flutterVersionCode = '1'
|
||||
}
|
||||
|
||||
def flutterVersionName = localProperties.getProperty('flutter.versionName')
|
||||
if (flutterVersionName == null) {
|
||||
flutterVersionName = '1.0'
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
ndkVersion '21.3.6528147'
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
lintOptions {
|
||||
disable 'InvalidPackage'
|
||||
checkReleaseBuilds false
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId "com.example.example"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
// TODO: Add your own signing config for the release build.
|
||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source '../..'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test:runner:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
|
||||
implementation 'com.google.firebase:firebase-messaging:20.1.2'
|
||||
}
|
||||
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
@@ -1,7 +0,0 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.example">
|
||||
<!-- Flutter needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
@@ -1,39 +0,0 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.example">
|
||||
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
|
||||
calls FlutterMain.startInitialization(this); in its onCreate method.
|
||||
In most cases you can leave this as-is, but you if you want to provide
|
||||
additional functionality it is fine to subclass or reimplement
|
||||
FlutterApplication and put your custom class here. -->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<application
|
||||
android:name=".Application"
|
||||
android:label="ChatSample"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
>
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.example.example
|
||||
|
||||
import com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin
|
||||
import io.flutter.app.FlutterApplication
|
||||
import io.flutter.plugin.common.PluginRegistry
|
||||
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
|
||||
import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin
|
||||
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService
|
||||
import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin
|
||||
import io.flutter.plugins.pathprovider.PathProviderPlugin
|
||||
|
||||
class Application : FlutterApplication(), PluginRegistrantCallback {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
FlutterFirebaseMessagingService.setPluginRegistrant(this)
|
||||
}
|
||||
|
||||
override fun registerWith(registry: PluginRegistry?) {
|
||||
PathProviderPlugin.registerWith(registry?.registrarFor(
|
||||
"io.flutter.plugins.pathprovider.PathProviderPlugin"))
|
||||
SharedPreferencesPlugin.registerWith(registry?.registrarFor(
|
||||
"io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin"))
|
||||
FlutterLocalNotificationsPlugin.registerWith(registry?.registrarFor(
|
||||
"com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin"))
|
||||
FirebaseMessagingPlugin.registerWith(registry?.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"))
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.example.example
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugins.GeneratedPluginRegistrant
|
||||
|
||||
class MainActivity: FlutterActivity() {
|
||||
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
||||
GeneratedPluginRegistrant.registerWith(flutterEngine);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 21 KiB |
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
Flutter draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,7 +0,0 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.example">
|
||||
<!-- Flutter needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
@@ -1,32 +0,0 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.50'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.6.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath 'com.google.gms:google-services:4.3.2'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.buildDir = '../build'
|
||||
subprojects {
|
||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||
}
|
||||
subprojects {
|
||||
project.evaluationDependsOn(':app')
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.enableR8=true
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
@@ -1,6 +0,0 @@
|
||||
#Thu Oct 22 11:03:39 CEST 2020
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
|
||||
@@ -1,15 +0,0 @@
|
||||
include ':app'
|
||||
|
||||
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
|
||||
|
||||
def plugins = new Properties()
|
||||
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
|
||||
if (pluginsFile.exists()) {
|
||||
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
|
||||
}
|
||||
|
||||
plugins.each { name, path ->
|
||||
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
|
||||
include ":$name"
|
||||
project(":$name").projectDir = pluginDirectory
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
include ':app'
|
||||
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,5 +0,0 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 12C3 11.4477 3.44772 11 4 11H20C20.5523 11 21 11.4477 21 12C21 12.5523 20.5523 13 20 13H4C3.44772 13 3 12.5523 3 12Z" fill="#006CFF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.2929 7.29289C15.6834 6.90237 16.3166 6.90237 16.7071 7.29289L20.7071 11.2929C21.0976 11.6834 21.0976 12.3166 20.7071 12.7071C20.3166 13.0976 19.6834 13.0976 19.2929 12.7071L15.2929 8.70711C14.9024 8.31658 14.9024 7.68342 15.2929 7.29289Z" fill="#006CFF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.7071 11.2929C21.0976 11.6834 21.0976 12.3166 20.7071 12.7071L16.7071 16.7071C16.3166 17.0976 15.6834 17.0976 15.2929 16.7071C14.9024 16.3166 14.9024 15.6834 15.2929 15.2929L19.2929 11.2929C19.6834 10.9024 20.3166 10.9024 20.7071 11.2929Z" fill="#006CFF"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 908 B |
|
Before Width: | Height: | Size: 40 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="80" height="40" viewBox="0 0 80 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M52.2984 12.8561L77.9046 11.0409C79.5948 10.9211 80.659 12.8259 79.6708 14.2023L61.7582 39.1527C61.3826 39.6759 60.7778 39.9863 60.1336 39.9863H19.9646C19.3214 39.9863 18.7174 39.6769 18.3414 39.1547L0.381197 14.2043C-0.609403 12.8281 0.454797 10.9207 2.1464 11.0409L27.6746 12.8563L38.578 0.666539C39.377 -0.226661 40.777 -0.221461 41.5694 0.677939L52.2984 12.8561ZM57.6608 36.0305L41.0426 29.8199V36.0305H57.6608ZM39.0426 36.0305V29.8199L22.4244 36.0305H39.0426ZM37.125 28.3363L20.146 34.6743L7.6548 17.3111L37.125 28.3363ZM42.9256 28.3363L59.9046 34.6743L72.3958 17.3111L42.9256 28.3363ZM39.0586 26.8871V5.98954L25.1758 21.6611L39.0586 26.8871ZM41.0426 26.8871V5.99214L54.9256 21.6611L41.0426 26.8871ZM21.1046 20.2165L24.2988 16.6273L8.6934 15.5089L21.1046 20.2165ZM58.8298 20.2165L55.6358 16.6273L71.2412 15.5089L58.8298 20.2165Z" fill="#006CFF"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1004 B |
@@ -1,32 +0,0 @@
|
||||
*.mode1v3
|
||||
*.mode2v3
|
||||
*.moved-aside
|
||||
*.pbxuser
|
||||
*.perspectivev3
|
||||
**/*sync/
|
||||
.sconsign.dblite
|
||||
.tags*
|
||||
**/.vagrant/
|
||||
**/DerivedData/
|
||||
Icon?
|
||||
**/Pods/
|
||||
**/.symlinks/
|
||||
profile
|
||||
xcuserdata
|
||||
**/.generated/
|
||||
Flutter/App.framework
|
||||
Flutter/Flutter.framework
|
||||
Flutter/Flutter.podspec
|
||||
Flutter/Generated.xcconfig
|
||||
Flutter/app.flx
|
||||
Flutter/app.zip
|
||||
Flutter/flutter_assets/
|
||||
Flutter/flutter_export_environment.sh
|
||||
ServiceDefinitions.json
|
||||
Runner/GeneratedPluginRegistrant.*
|
||||
|
||||
# Exceptions to above rules.
|
||||
!default.mode1v3
|
||||
!default.mode2v3
|
||||
!default.pbxuser
|
||||
!default.perspectivev3
|
||||
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>App</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>io.flutter.flutter.app</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>App</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>8.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
@@ -1,6 +0,0 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "fastlane"
|
||||
|
||||
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
|
||||
eval_gemfile(plugins_path) if File.exist?(plugins_path)
|
||||
@@ -1,180 +0,0 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (3.0.2)
|
||||
addressable (2.7.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.1.0)
|
||||
aws-partitions (1.380.0)
|
||||
aws-sdk-core (3.109.1)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.239.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
jmespath (~> 1.0)
|
||||
aws-sdk-kms (1.39.0)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.83.0)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sigv4 (1.2.2)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
babosa (1.0.3)
|
||||
claide (1.0.3)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
commander-fastlane (4.4.6)
|
||||
highline (~> 1.7.2)
|
||||
declarative (0.0.20)
|
||||
declarative-option (0.1.0)
|
||||
digest-crc (0.6.1)
|
||||
rake (~> 13.0)
|
||||
domain_name (0.5.20190701)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
dotenv (2.7.6)
|
||||
emoji_regex (3.0.0)
|
||||
excon (0.76.0)
|
||||
faraday (1.0.1)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
faraday-cookie_jar (0.0.7)
|
||||
faraday (>= 0.8.0)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday_middleware (1.0.0)
|
||||
faraday (~> 1.0)
|
||||
fastimage (2.2.0)
|
||||
fastlane (2.162.0)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.3, < 3.0.0)
|
||||
aws-sdk-s3 (~> 1.0)
|
||||
babosa (>= 1.0.3, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 3.0.0)
|
||||
colored
|
||||
commander-fastlane (>= 4.4.6, < 5.0.0)
|
||||
dotenv (>= 2.1.1, < 3.0.0)
|
||||
emoji_regex (>= 0.1, < 4.0)
|
||||
excon (>= 0.71.0, < 1.0.0)
|
||||
faraday (~> 1.0)
|
||||
faraday-cookie_jar (~> 0.0.6)
|
||||
faraday_middleware (~> 1.0)
|
||||
fastimage (>= 2.1.0, < 3.0.0)
|
||||
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||
google-api-client (>= 0.37.0, < 0.39.0)
|
||||
google-cloud-storage (>= 1.15.0, < 2.0.0)
|
||||
highline (>= 1.7.2, < 2.0.0)
|
||||
json (< 3.0.0)
|
||||
jwt (>= 2.1.0, < 3)
|
||||
mini_magick (>= 4.9.4, < 5.0.0)
|
||||
multipart-post (~> 2.0.0)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
rubyzip (>= 2.0.0, < 3.0.0)
|
||||
security (= 0.1.3)
|
||||
simctl (~> 1.6.3)
|
||||
slack-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-table (>= 1.4.5, < 2.0.0)
|
||||
tty-screen (>= 0.6.3, < 1.0.0)
|
||||
tty-spinner (>= 0.8.0, < 1.0.0)
|
||||
word_wrap (~> 1.0.0)
|
||||
xcodeproj (>= 1.13.0, < 2.0.0)
|
||||
xcpretty (~> 0.3.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3)
|
||||
fastlane-plugin-firebase_app_distribution (0.2.3)
|
||||
gh_inspector (1.1.3)
|
||||
google-api-client (0.38.0)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (~> 0.9)
|
||||
httpclient (>= 2.8.1, < 3.0)
|
||||
mini_mime (~> 1.0)
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.0)
|
||||
signet (~> 0.12)
|
||||
google-cloud-core (1.5.0)
|
||||
google-cloud-env (~> 1.0)
|
||||
google-cloud-errors (~> 1.0)
|
||||
google-cloud-env (1.3.3)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
google-cloud-errors (1.0.1)
|
||||
google-cloud-storage (1.29.1)
|
||||
addressable (~> 2.5)
|
||||
digest-crc (~> 0.4)
|
||||
google-api-client (~> 0.33)
|
||||
google-cloud-core (~> 1.2)
|
||||
googleauth (~> 0.9)
|
||||
mini_mime (~> 1.0)
|
||||
googleauth (0.13.1)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
memoist (~> 0.16)
|
||||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (~> 0.14)
|
||||
highline (1.7.10)
|
||||
http-cookie (1.0.3)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
jmespath (1.4.0)
|
||||
json (2.3.1)
|
||||
jwt (2.2.2)
|
||||
memoist (0.16.2)
|
||||
mini_magick (4.10.1)
|
||||
mini_mime (1.0.2)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.0.0)
|
||||
nanaimo (0.3.0)
|
||||
naturally (2.2.0)
|
||||
os (1.1.1)
|
||||
plist (3.5.0)
|
||||
public_suffix (4.0.6)
|
||||
rake (13.0.1)
|
||||
representable (3.0.4)
|
||||
declarative (< 0.1.0)
|
||||
declarative-option (< 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rouge (2.0.7)
|
||||
rubyzip (2.3.0)
|
||||
security (0.1.3)
|
||||
signet (0.14.0)
|
||||
addressable (~> 2.3)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simctl (1.6.8)
|
||||
CFPropertyList
|
||||
naturally
|
||||
slack-notifier (2.3.2)
|
||||
terminal-notifier (2.0.0)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
tty-cursor (0.7.1)
|
||||
tty-screen (0.8.1)
|
||||
tty-spinner (0.9.3)
|
||||
tty-cursor (~> 0.7)
|
||||
uber (0.1.0)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.7)
|
||||
unicode-display_width (1.7.0)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.18.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.3.0)
|
||||
xcpretty (0.3.0)
|
||||
rouge (~> 2.0.7)
|
||||
xcpretty-travis-formatter (1.0.0)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
fastlane
|
||||
fastlane-plugin-firebase_app_distribution
|
||||
|
||||
BUNDLED WITH
|
||||
2.0.2
|
||||
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Notifications</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.usernotifications.service</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).NotificationService</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,182 +0,0 @@
|
||||
//
|
||||
// NotificationService.swift
|
||||
// Notifications
|
||||
//
|
||||
// Created by Salvatore Giordano on 25/03/2020.
|
||||
// Copyright © 2020 The Chromium Authors. All rights reserved.
|
||||
//
|
||||
|
||||
import UserNotifications
|
||||
//import StreamChatClient
|
||||
|
||||
final class NotificationService: UNNotificationServiceExtension {
|
||||
|
||||
var contentHandler: ((UNNotificationContent) -> Void)?
|
||||
var bestAttemptContent: UNMutableNotificationContent?
|
||||
|
||||
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
|
||||
self.contentHandler = contentHandler
|
||||
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
|
||||
|
||||
guard let sharedDefaults = UserDefaults(suiteName: "group.io.getstream.flutter"),
|
||||
let apiKey = sharedDefaults.string(forKey: "KEY_API_KEY"),
|
||||
let userId = sharedDefaults.string(forKey: "KEY_USER_ID"),
|
||||
let token = sharedDefaults.string(forKey: "KEY_TOKEN"),
|
||||
let messageId = bestAttemptContent?.userInfo["message_id"] as? String else {
|
||||
return
|
||||
}
|
||||
|
||||
// Client.config = .init(apiKey: apiKey, logOptions: .error)
|
||||
// Client.shared.set(user: User(id: userId), token: token) { res in
|
||||
// guard res.isConnected else {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// Client.shared.message(withId: messageId) { [weak self] res in
|
||||
// if let message = res.value?.message,
|
||||
// let channel = res.value?.channel {
|
||||
// let messageWrapper = MessageWrapper(channel: channel, message: message)
|
||||
// if let encodedData = try? JSONEncoder.stream.encode(messageWrapper),
|
||||
// let encodedString = String(data: encodedData, encoding: .utf8) {
|
||||
// let storedMessages = sharedDefaults.stringArray(forKey: "messageQueue") ?? []
|
||||
// sharedDefaults.setValue(storedMessages + [encodedString], forKey: "messageQueue")
|
||||
//
|
||||
// // Modify the notification content here...
|
||||
// self?.bestAttemptContent?.title = "[modified] \(self?.bestAttemptContent?.title ?? "<NoContent>")"
|
||||
// contentHandler(self?.bestAttemptContent ?? request.content)
|
||||
// }
|
||||
// Client.shared.disconnect()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
override func serviceExtensionTimeWillExpire() {
|
||||
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
|
||||
contentHandler(bestAttemptContent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//public struct MessageWrapper: Encodable {
|
||||
// private enum CodingKeys: String, CodingKey {
|
||||
// case id
|
||||
// case channel
|
||||
// case type
|
||||
// case user
|
||||
// case created = "created_at"
|
||||
// case updated = "updated_at"
|
||||
// case text
|
||||
// case command
|
||||
// case args
|
||||
// case attachments
|
||||
// case parentId = "parent_id"
|
||||
// case showReplyInChannel = "show_in_channel"
|
||||
// case mentionedUsers = "mentioned_users"
|
||||
// }
|
||||
//
|
||||
// init(channel: Channel, message: Message) {
|
||||
// id = message.id
|
||||
// type = message.type
|
||||
// user = message.user
|
||||
// created = message.created
|
||||
// updated = message.updated
|
||||
// text = message.text
|
||||
// command = message.command
|
||||
// args = message.args
|
||||
// attachments = message.attachments
|
||||
// parentId = message.parentId
|
||||
// showReplyInChannel = message.showReplyInChannel
|
||||
// mentionedUsers = message.mentionedUsers
|
||||
// extraData = message.extraData
|
||||
// self.channel = ChannelWrapper(channel: channel)
|
||||
// }
|
||||
//
|
||||
// /// A message id.
|
||||
// public let id: String
|
||||
// /// The channel cid.
|
||||
// public let channel: ChannelWrapper?
|
||||
// /// A message type (see `MessageType`).
|
||||
// public let type: MessageType
|
||||
// /// A user (see `User`).
|
||||
// public let user: User
|
||||
// /// A created date.
|
||||
// public let created: Date
|
||||
// /// A updated date.
|
||||
// public let updated: Date
|
||||
// /// A text.
|
||||
// public let text: String
|
||||
// /// A used command name.
|
||||
// public let command: String?
|
||||
// /// A used command args.
|
||||
// public let args: String?
|
||||
// /// Attachments (see `Attachment`).
|
||||
// public let attachments: [Attachment]
|
||||
// /// A parent message id.
|
||||
// public let parentId: String?
|
||||
// /// Check if this reply message needs to show in the channel.
|
||||
// public let showReplyInChannel: Bool
|
||||
// /// Mentioned users (see `User`).
|
||||
// public let mentionedUsers: [User]
|
||||
// /// An extra data for the message.
|
||||
// public let extraData: Codable?
|
||||
//}
|
||||
//
|
||||
//public struct ChannelWrapper: Encodable {
|
||||
// /// Coding keys for the encoding.
|
||||
// private enum CodingKeys: String, CodingKey {
|
||||
// case id
|
||||
// case cid
|
||||
// case type
|
||||
// case name
|
||||
// case imageURL = "image"
|
||||
// case members
|
||||
// case lastMessageDate = "last_message_at"
|
||||
// case createdBy = "created_by"
|
||||
// case created = "created_at"
|
||||
// case deleted = "deleted_at"
|
||||
// case frozen
|
||||
// }
|
||||
//
|
||||
// init(channel: Channel) {
|
||||
// id = channel.id
|
||||
// cid = channel.cid
|
||||
// type = channel.type
|
||||
// name = channel.name
|
||||
// imageURL = channel.imageURL
|
||||
// lastMessageDate = channel.lastMessageDate
|
||||
// created = channel.created
|
||||
// deleted = channel.deleted
|
||||
// createdBy = channel.createdBy
|
||||
// config = channel.config
|
||||
// frozen = channel.frozen
|
||||
// extraData = channel.extraData
|
||||
// }
|
||||
//
|
||||
// /// A channel id.
|
||||
// public let id: String
|
||||
// /// A channel type + id.
|
||||
// public let cid: ChannelId
|
||||
// /// A channel type.
|
||||
// public let type: ChannelType
|
||||
// /// A channel name.
|
||||
// public let name: String?
|
||||
// /// An image of the channel.
|
||||
// public let imageURL: URL?
|
||||
// /// The last message date.
|
||||
// public let lastMessageDate: Date?
|
||||
// /// A channel created date.
|
||||
// public let created: Date
|
||||
// /// A channel deleted date.
|
||||
// public let deleted: Date?
|
||||
// /// A creator of the channel.
|
||||
// public let createdBy: User?
|
||||
// /// A config.
|
||||
// public let config: Channel.Config
|
||||
// /// Checks if the channel is frozen.
|
||||
// public let frozen: Bool
|
||||
// /// A list of user ids of the channel members.
|
||||
// public let members = Set<Member>()
|
||||
// /// An extra data for the channel.
|
||||
// public let extraData: Codable?
|
||||
//}
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.io.getstream.flutter</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,43 +0,0 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
platform :ios, '11.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_ios_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
use_frameworks!
|
||||
use_modular_headers!
|
||||
|
||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||
end
|
||||
|
||||
pod 'StreamChatClient'
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
end
|
||||
end
|
||||
@@ -1,299 +0,0 @@
|
||||
PODS:
|
||||
- DKImagePickerController/Core (4.3.2):
|
||||
- DKImagePickerController/ImageDataManager
|
||||
- DKImagePickerController/Resource
|
||||
- DKImagePickerController/ImageDataManager (4.3.2)
|
||||
- DKImagePickerController/PhotoGallery (4.3.2):
|
||||
- DKImagePickerController/Core
|
||||
- DKPhotoGallery
|
||||
- DKImagePickerController/Resource (4.3.2)
|
||||
- DKPhotoGallery (0.0.17):
|
||||
- DKPhotoGallery/Core (= 0.0.17)
|
||||
- DKPhotoGallery/Model (= 0.0.17)
|
||||
- DKPhotoGallery/Preview (= 0.0.17)
|
||||
- DKPhotoGallery/Resource (= 0.0.17)
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Core (0.0.17):
|
||||
- DKPhotoGallery/Model
|
||||
- DKPhotoGallery/Preview
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Model (0.0.17):
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Preview (0.0.17):
|
||||
- DKPhotoGallery/Model
|
||||
- DKPhotoGallery/Resource
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Resource (0.0.17):
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- esys_flutter_share (0.0.1):
|
||||
- Flutter
|
||||
- file_picker (0.0.1):
|
||||
- DKImagePickerController/PhotoGallery
|
||||
- Flutter
|
||||
- Firebase/CoreOnly (6.33.0):
|
||||
- FirebaseCore (= 6.10.3)
|
||||
- Firebase/Messaging (6.33.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseMessaging (~> 4.7.0)
|
||||
- firebase_core (0.5.3):
|
||||
- Firebase/CoreOnly (~> 6.33.0)
|
||||
- Flutter
|
||||
- firebase_messaging (7.0.3):
|
||||
- Firebase/CoreOnly (~> 6.33.0)
|
||||
- Firebase/Messaging (~> 6.33.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- FirebaseCore (6.10.3):
|
||||
- FirebaseCoreDiagnostics (~> 1.6)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/Logger (~> 6.7)
|
||||
- FirebaseCoreDiagnostics (1.7.0):
|
||||
- GoogleDataTransport (~> 7.4)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/Logger (~> 6.7)
|
||||
- nanopb (~> 1.30906.0)
|
||||
- FirebaseInstallations (1.7.0):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/UserDefaults (~> 6.7)
|
||||
- PromisesObjC (~> 1.2)
|
||||
- FirebaseInstanceID (4.8.0):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- FirebaseInstallations (~> 1.6)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/UserDefaults (~> 6.7)
|
||||
- FirebaseMessaging (4.7.1):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- FirebaseInstanceID (~> 4.7)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.7)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/Reachability (~> 6.7)
|
||||
- GoogleUtilities/UserDefaults (~> 6.7)
|
||||
- Protobuf (>= 3.9.2, ~> 3.9)
|
||||
- Flutter (1.0.0)
|
||||
- flutter_apns (0.0.1):
|
||||
- Flutter
|
||||
- flutter_app_badger (0.0.1):
|
||||
- Flutter
|
||||
- flutter_keyboard_visibility (0.0.1):
|
||||
- Flutter
|
||||
- flutter_local_notifications (0.0.1):
|
||||
- Flutter
|
||||
- flutter_secure_storage (3.3.1):
|
||||
- Flutter
|
||||
- FMDB (2.7.5):
|
||||
- FMDB/standard (= 2.7.5)
|
||||
- FMDB/standard (2.7.5)
|
||||
- GoogleDataTransport (7.5.1):
|
||||
- nanopb (~> 1.30906.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (6.7.2):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Environment (6.7.2):
|
||||
- PromisesObjC (~> 1.2)
|
||||
- GoogleUtilities/Logger (6.7.2):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Network (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (6.7.2)"
|
||||
- GoogleUtilities/Reachability (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/UserDefaults (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- image_gallery_saver (1.5.0):
|
||||
- Flutter
|
||||
- image_picker (0.0.1):
|
||||
- Flutter
|
||||
- nanopb (1.30906.0):
|
||||
- nanopb/decode (= 1.30906.0)
|
||||
- nanopb/encode (= 1.30906.0)
|
||||
- nanopb/decode (1.30906.0)
|
||||
- nanopb/encode (1.30906.0)
|
||||
- path_provider (0.0.1):
|
||||
- Flutter
|
||||
- photo_manager (0.0.1):
|
||||
- Flutter
|
||||
- PromisesObjC (1.2.11)
|
||||
- Protobuf (3.13.0)
|
||||
- SDWebImage (5.10.0):
|
||||
- SDWebImage/Core (= 5.10.0)
|
||||
- SDWebImage/Core (5.10.0)
|
||||
- shared_preferences (0.0.1):
|
||||
- Flutter
|
||||
- sqflite (0.0.2):
|
||||
- Flutter
|
||||
- FMDB (>= 2.7.5)
|
||||
- sqlite3 (3.32.3):
|
||||
- sqlite3/common (= 3.32.3)
|
||||
- sqlite3/common (3.32.3)
|
||||
- sqlite3/fts5 (3.32.3):
|
||||
- sqlite3/common
|
||||
- sqlite3/json1 (3.32.3):
|
||||
- sqlite3/common
|
||||
- sqlite3/perf-threadsafe (3.32.3):
|
||||
- sqlite3/common
|
||||
- sqlite3/rtree (3.32.3):
|
||||
- sqlite3/common
|
||||
- sqlite3_flutter_libs (0.0.1):
|
||||
- Flutter
|
||||
- sqlite3 (~> 3.32.3)
|
||||
- sqlite3/fts5
|
||||
- sqlite3/json1
|
||||
- sqlite3/perf-threadsafe
|
||||
- sqlite3/rtree
|
||||
- Starscream (4.0.4)
|
||||
- StreamChatClient (2.4.2):
|
||||
- Starscream (~> 4.0)
|
||||
- SwiftyGif (5.3.0)
|
||||
- url_launcher (0.0.1):
|
||||
- Flutter
|
||||
- video_compress (0.3.0):
|
||||
- Flutter
|
||||
- video_player (0.0.1):
|
||||
- Flutter
|
||||
- wakelock (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- esys_flutter_share (from `.symlinks/plugins/esys_flutter_share/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_apns (from `.symlinks/plugins/flutter_apns/ios`)
|
||||
- flutter_app_badger (from `.symlinks/plugins/flutter_app_badger/ios`)
|
||||
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||
- image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/ios`)
|
||||
- image_picker (from `.symlinks/plugins/image_picker/ios`)
|
||||
- path_provider (from `.symlinks/plugins/path_provider/ios`)
|
||||
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
|
||||
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
|
||||
- sqflite (from `.symlinks/plugins/sqflite/ios`)
|
||||
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`)
|
||||
- StreamChatClient
|
||||
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
|
||||
- video_compress (from `.symlinks/plugins/video_compress/ios`)
|
||||
- video_player (from `.symlinks/plugins/video_player/ios`)
|
||||
- wakelock (from `.symlinks/plugins/wakelock/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- DKImagePickerController
|
||||
- DKPhotoGallery
|
||||
- Firebase
|
||||
- FirebaseCore
|
||||
- FirebaseCoreDiagnostics
|
||||
- FirebaseInstallations
|
||||
- FirebaseInstanceID
|
||||
- FirebaseMessaging
|
||||
- FMDB
|
||||
- GoogleDataTransport
|
||||
- GoogleUtilities
|
||||
- nanopb
|
||||
- PromisesObjC
|
||||
- Protobuf
|
||||
- SDWebImage
|
||||
- sqlite3
|
||||
- Starscream
|
||||
- StreamChatClient
|
||||
- SwiftyGif
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
esys_flutter_share:
|
||||
:path: ".symlinks/plugins/esys_flutter_share/ios"
|
||||
file_picker:
|
||||
:path: ".symlinks/plugins/file_picker/ios"
|
||||
firebase_core:
|
||||
:path: ".symlinks/plugins/firebase_core/ios"
|
||||
firebase_messaging:
|
||||
:path: ".symlinks/plugins/firebase_messaging/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_apns:
|
||||
:path: ".symlinks/plugins/flutter_apns/ios"
|
||||
flutter_app_badger:
|
||||
:path: ".symlinks/plugins/flutter_app_badger/ios"
|
||||
flutter_keyboard_visibility:
|
||||
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
|
||||
flutter_local_notifications:
|
||||
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
||||
flutter_secure_storage:
|
||||
:path: ".symlinks/plugins/flutter_secure_storage/ios"
|
||||
image_gallery_saver:
|
||||
:path: ".symlinks/plugins/image_gallery_saver/ios"
|
||||
image_picker:
|
||||
:path: ".symlinks/plugins/image_picker/ios"
|
||||
path_provider:
|
||||
:path: ".symlinks/plugins/path_provider/ios"
|
||||
photo_manager:
|
||||
:path: ".symlinks/plugins/photo_manager/ios"
|
||||
shared_preferences:
|
||||
:path: ".symlinks/plugins/shared_preferences/ios"
|
||||
sqflite:
|
||||
:path: ".symlinks/plugins/sqflite/ios"
|
||||
sqlite3_flutter_libs:
|
||||
:path: ".symlinks/plugins/sqlite3_flutter_libs/ios"
|
||||
url_launcher:
|
||||
:path: ".symlinks/plugins/url_launcher/ios"
|
||||
video_compress:
|
||||
:path: ".symlinks/plugins/video_compress/ios"
|
||||
video_player:
|
||||
:path: ".symlinks/plugins/video_player/ios"
|
||||
wakelock:
|
||||
:path: ".symlinks/plugins/wakelock/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d
|
||||
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
||||
esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4
|
||||
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
|
||||
Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5
|
||||
firebase_core: 5d6a02f3d85acd5f8321c2d6d62877626a670659
|
||||
firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75
|
||||
FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd
|
||||
FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1
|
||||
FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2
|
||||
FirebaseInstanceID: bd3ffc24367f901a43c063b36c640b345a4a5dd1
|
||||
FirebaseMessaging: 5eca4ef173de76253352511aafef774caa1cba2a
|
||||
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
|
||||
flutter_apns: ddc629f26016140bf52165040b0a8e8869f9ce32
|
||||
flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68
|
||||
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
|
||||
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743
|
||||
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
|
||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||
GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833
|
||||
GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
|
||||
image_gallery_saver: 259eab68fb271cfd57d599904f7acdc7832e7ef2
|
||||
image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09
|
||||
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
|
||||
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
|
||||
photo_manager: f7c619c2cc8c2adb8d85c63363babac477de9c67
|
||||
PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f
|
||||
Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748
|
||||
SDWebImage: 9169792e9eec3e45bba2a0c02f74bf8bd922d1ee
|
||||
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
|
||||
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
|
||||
sqlite3: 8f7d2078ae27778699a622a94b853285793422a2
|
||||
sqlite3_flutter_libs: 5651f8ff48e3b44d910863c4ea5916085b1b245f
|
||||
Starscream: 5178aed56b316f13fa3bc55694e583d35dd414d9
|
||||
StreamChatClient: fc6419fa7ceda9c048188bb7c8e9f07755ced05f
|
||||
SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40
|
||||
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
|
||||
video_compress: fce97e4fb1dfd88175aa07d2ffc8a2f297f87fbe
|
||||
video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e
|
||||
wakelock: bfc7955c418d0db797614075aabbc58a39ab5107
|
||||
|
||||
PODFILE CHECKSUM: eb001256612a59f8f9e4d083ad8b9671e69dd184
|
||||
|
||||
COCOAPODS: 1.10.0
|
||||
@@ -1,845 +0,0 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
0BC14C50242B5A7A0028DE94 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BC14C4F242B5A7A0028DE94 /* NotificationService.swift */; };
|
||||
0BC14C54242B5A7A0028DE94 /* Notifications.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 0BC14C4D242B5A7A0028DE94 /* Notifications.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
7DEC2743BD66C91B700A3B97 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BB2E5E4E236267EDF0D8817 /* Pods_Runner.framework */; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
0BC14C52242B5A7A0028DE94 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 0BC14C4C242B5A7A0028DE94;
|
||||
remoteInfo = Notifications;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
0BC14C55242B5A7A0028DE94 /* Embed App Extensions */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
0BC14C54242B5A7A0028DE94 /* Notifications.appex in Embed App Extensions */,
|
||||
);
|
||||
name = "Embed App Extensions";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0BC14C4D242B5A7A0028DE94 /* Notifications.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Notifications.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0BC14C4F242B5A7A0028DE94 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
|
||||
0BC14C51242B5A7A0028DE94 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
0BC14C5A242B5ED90028DE94 /* Notifications.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Notifications.entitlements; sourceTree = "<group>"; };
|
||||
0BC14C5B242B5FF50028DE94 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
2452A9E77396497EB4CF3072 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
68F846A6DB42D92393F5F7E0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
7BF51EE28C89025F73A5211F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
8BB2E5E4E236267EDF0D8817 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
0BC14C4A242B5A7A0028DE94 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
7DEC2743BD66C91B700A3B97 /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
0BC14C4E242B5A7A0028DE94 /* Notifications */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0BC14C5A242B5ED90028DE94 /* Notifications.entitlements */,
|
||||
0BC14C4F242B5A7A0028DE94 /* NotificationService.swift */,
|
||||
0BC14C51242B5A7A0028DE94 /* Info.plist */,
|
||||
);
|
||||
path = Notifications;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
||||
);
|
||||
name = Flutter;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146E51CF9000F007C117D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
0BC14C4E242B5A7A0028DE94 /* Notifications */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
CF168B61BAB91958681C7C21 /* Pods */,
|
||||
BC09A38346C8B2CD72199469 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146EF1CF9000F007C117D /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
0BC14C4D242B5A7A0028DE94 /* Notifications.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146F01CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0BC14C5B242B5FF50028DE94 /* Runner.entitlements */,
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||
97C147021CF9000F007C117D /* Info.plist */,
|
||||
97C146F11CF9000F007C117D /* Supporting Files */,
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||
);
|
||||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146F11CF9000F007C117D /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BC09A38346C8B2CD72199469 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8BB2E5E4E236267EDF0D8817 /* Pods_Runner.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CF168B61BAB91958681C7C21 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2452A9E77396497EB4CF3072 /* Pods-Runner.debug.xcconfig */,
|
||||
7BF51EE28C89025F73A5211F /* Pods-Runner.release.xcconfig */,
|
||||
68F846A6DB42D92393F5F7E0 /* Pods-Runner.profile.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
0BC14C4C242B5A7A0028DE94 /* Notifications */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 0BC14C59242B5A7A0028DE94 /* Build configuration list for PBXNativeTarget "Notifications" */;
|
||||
buildPhases = (
|
||||
0BC14C49242B5A7A0028DE94 /* Sources */,
|
||||
0BC14C4A242B5A7A0028DE94 /* Frameworks */,
|
||||
0BC14C4B242B5A7A0028DE94 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Notifications;
|
||||
productName = Notifications;
|
||||
productReference = 0BC14C4D242B5A7A0028DE94 /* Notifications.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
9E02B5C38D6CC2455D9E48E9 /* [CP] Check Pods Manifest.lock */,
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
5702861DACEDB848A3E454E8 /* [CP] Embed Pods Frameworks */,
|
||||
0BC14C55242B5A7A0028DE94 /* Embed App Extensions */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
0BC14C53242B5A7A0028DE94 /* PBXTargetDependency */,
|
||||
);
|
||||
name = Runner;
|
||||
productName = Runner;
|
||||
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
97C146E61CF9000F007C117D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1140;
|
||||
LastUpgradeCheck = 1020;
|
||||
ORGANIZATIONNAME = "The Chromium Authors";
|
||||
TargetAttributes = {
|
||||
0BC14C4C242B5A7A0028DE94 = {
|
||||
CreatedOnToolsVersion = 11.4;
|
||||
DevelopmentTeam = EHV7XZLAHA;
|
||||
ProvisioningStyle = Manual;
|
||||
};
|
||||
97C146ED1CF9000F007C117D = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
DevelopmentTeam = EHV7XZLAHA;
|
||||
LastSwiftMigration = 1100;
|
||||
ProvisioningStyle = Manual;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 97C146E51CF9000F007C117D;
|
||||
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
97C146ED1CF9000F007C117D /* Runner */,
|
||||
0BC14C4C242B5A7A0028DE94 /* Notifications */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
0BC14C4B242B5A7A0028DE94 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Thin Binary";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
5702861DACEDB848A3E454E8 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
|
||||
"${BUILT_PRODUCTS_DIR}/Starscream-framework/Starscream.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/StreamChatClient-framework/StreamChatClient.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework",
|
||||
"${PODS_ROOT}/../Flutter/Flutter.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/esys_flutter_share/esys_flutter_share.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/flutter_apns/flutter_apns.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/flutter_app_badger/flutter_app_badger.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/flutter_keyboard_visibility/flutter_keyboard_visibility.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/flutter_secure_storage/flutter_secure_storage.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/image_gallery_saver/image_gallery_saver.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/photo_manager/photo_manager.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/sqlite3_flutter_libs/sqlite3_flutter_libs.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/video_compress/video_compress.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/video_player/video_player.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/wakelock/wakelock.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Starscream.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/StreamChatClient.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/esys_flutter_share.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_apns.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_app_badger.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_keyboard_visibility.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_secure_storage.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_gallery_saver.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_manager.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3_flutter_libs.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_compress.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_player.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Run Script";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
};
|
||||
9E02B5C38D6CC2455D9E48E9 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
0BC14C49242B5A7A0028DE94 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0BC14C50242B5A7A0028DE94 /* NotificationService.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
0BC14C53242B5A7A0028DE94 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 0BC14C4C242B5A7A0028DE94 /* Notifications */;
|
||||
targetProxy = 0BC14C52242B5A7A0028DE94 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
97C146FB1CF9000F007C117D /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
97C147001CF9000F007C117D /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
0BC14C56242B5A7A0028DE94 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = Notifications/Notifications.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = EHV7XZLAHA;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = Notifications/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.3;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter.Notifications;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter.Notifications";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
0BC14C57242B5A7A0028DE94 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = Notifications/Notifications.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = EHV7XZLAHA;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = Notifications/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.3;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter.Notifications;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter.Notifications";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
0BC14C58242B5A7A0028DE94 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = Notifications/Notifications.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = EHV7XZLAHA;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = Notifications/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.3;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter.Notifications;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter.Notifications";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
249021D3217E4FDB00AE95B9 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = EHV7XZLAHA;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
97C147031CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
97C147041CF9000F007C117D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
97C147061CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = EHV7XZLAHA;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
97C147071CF9000F007C117D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = EHV7XZLAHA;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
0BC14C59242B5A7A0028DE94 /* Build configuration list for PBXNativeTarget "Notifications" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
0BC14C56242B5A7A0028DE94 /* Debug */,
|
||||
0BC14C57242B5A7A0028DE94 /* Release */,
|
||||
0BC14C58242B5A7A0028DE94 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
97C147031CF9000F007C117D /* Debug */,
|
||||
97C147041CF9000F007C117D /* Release */,
|
||||
249021D3217E4FDB00AE95B9 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
97C147061CF9000F007C117D /* Debug */,
|
||||
97C147071CF9000F007C117D /* Release */,
|
||||
249021D4217E4FDB00AE95B9 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PreviewsEnabled</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,96 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1160"
|
||||
wasCreatedForAppExtension = "YES"
|
||||
version = "2.0">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0BC14C4C242B5A7A0028DE94"
|
||||
BuildableName = "Notifications.appex"
|
||||
BlueprintName = "Notifications"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = ""
|
||||
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||
launchStyle = "0"
|
||||
askForAppToLaunch = "Yes"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES"
|
||||
launchAutomaticallySubstyle = "2">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
launchAutomaticallySubstyle = "2">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -1,87 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Profile"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PreviewsEnabled</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,45 +0,0 @@
|
||||
import UIKit
|
||||
import Flutter
|
||||
|
||||
@UIApplicationMain
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
let sharedDefaults = UserDefaults(suiteName: "group.io.getstream.flutter")
|
||||
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
if let messageQueue = sharedDefaults?.stringArray(forKey: "messageQueue") {
|
||||
UserDefaults.standard.setValue(messageQueue, forKey: "flutter.messageQueue")
|
||||
sharedDefaults?.removeObject(forKey: "messageQueue")
|
||||
}
|
||||
|
||||
if #available(iOS 10.0, *) {
|
||||
UNUserNotificationCenter.current().delegate = self
|
||||
}
|
||||
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
|
||||
override func applicationDidEnterBackground(_ application: UIApplication) {
|
||||
if let apiKey = UserDefaults.standard.string(forKey: "flutter.KEY_API_KEY") {
|
||||
sharedDefaults?.setValue(apiKey, forKey: "KEY_API_KEY")
|
||||
}
|
||||
|
||||
if let token = UserDefaults.standard.string(forKey: "flutter.KEY_TOKEN") {
|
||||
sharedDefaults?.setValue(token, forKey: "KEY_TOKEN")
|
||||
}
|
||||
|
||||
if let userId = UserDefaults.standard.string(forKey: "flutter.KEY_USER_ID") {
|
||||
sharedDefaults?.setValue(userId, forKey: "KEY_USER_ID")
|
||||
}
|
||||
}
|
||||
|
||||
override func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
if let messageQueue = sharedDefaults?.stringArray(forKey: "messageQueue") {
|
||||
UserDefaults.standard.setValue(messageQueue, forKey: "flutter.messageQueue")
|
||||
sharedDefaults?.removeObject(forKey: "messageQueue")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 572 B |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 990 B |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 7.4 KiB |
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "[email protected]",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 68 B |
|
Before Width: | Height: | Size: 68 B |
|
Before Width: | Height: | Size: 68 B |
@@ -1,5 +0,0 @@
|
||||
# Launch Screen Assets
|
||||
|
||||
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
|
||||
|
||||
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
|
||||
@@ -1,37 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="LaunchImage" width="168" height="185"/>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Flutter View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -1,64 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>ChatSample</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppleMusicUsageDescription</key>
|
||||
<string>Used to send message attachments</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Used to send message attachments</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Used to send message attachments</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Used to send message attachments</string>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>fetch</string>
|
||||
<string>remote-notification</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>remote-notification</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1 +0,0 @@
|
||||
#import "GeneratedPluginRegistrant.h"
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.io.getstream.flutter</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,6 +0,0 @@
|
||||
# app_identifier("[[APP_IDENTIFIER]]") # The bundle identifier of your app
|
||||
# apple_id("[[APPLE_ID]]") # Your Apple email address
|
||||
|
||||
|
||||
# For more information about the Appfile, see:
|
||||
# https://docs.fastlane.tools/advanced/#appfile
|
||||
@@ -1,46 +0,0 @@
|
||||
fastlane_version "2.162.0"
|
||||
default_platform :ios
|
||||
|
||||
before_all do
|
||||
if is_ci
|
||||
setup_ci()
|
||||
end
|
||||
end
|
||||
|
||||
desc "Installs all Certs and Profiles necessary for development and ad-hoc"
|
||||
lane :match_me do
|
||||
match(
|
||||
type: "adhoc",
|
||||
app_identifier: [
|
||||
"io.getstream.flutter",
|
||||
"io.getstream.flutter.Notifications"
|
||||
],
|
||||
readonly: is_ci,
|
||||
force_for_new_devices: true
|
||||
)
|
||||
end
|
||||
|
||||
platform :ios do
|
||||
desc "Deploy build to Firebase"
|
||||
lane :deploy_to_firebase do
|
||||
match_me
|
||||
|
||||
gym(
|
||||
workspace: "./Runner.xcworkspace",
|
||||
scheme: "Runner",
|
||||
export_method: "ad-hoc",
|
||||
export_options: "./fastlane/beta_gym_export_options.plist",
|
||||
silent: true,
|
||||
clean: true,
|
||||
include_symbols: true,
|
||||
output_directory: "./dist"
|
||||
)
|
||||
|
||||
message = changelog_from_git_commits(commits_count: 10)
|
||||
|
||||
firebase_app_distribution(
|
||||
app: "1:674907137625:ios:cafb9fb076a453c4d7f348",
|
||||
groups: "ios-stream-testers"
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -1,16 +0,0 @@
|
||||
git_url("https://github.com/GetStream/ios-certificates")
|
||||
|
||||
storage_mode("git")
|
||||
|
||||
username("[email protected]")
|
||||
|
||||
team_id("EHV7XZLAHA")
|
||||
|
||||
# app_identifier(["tools.fastlane.app", "tools.fastlane.app2"])
|
||||
|
||||
# username("[email protected]") # Your Apple Developer Portal username
|
||||
|
||||
# For all available options run `fastlane match --help`
|
||||
# Remove the # in the beginning of the line to enable the other options
|
||||
|
||||
# The docs are available on https://docs.fastlane.tools/actions/match
|
||||
@@ -1,5 +0,0 @@
|
||||
# Autogenerated by fastlane
|
||||
#
|
||||
# Ensure this file is checked in to source control!
|
||||
|
||||
gem 'fastlane-plugin-firebase_app_distribution'
|
||||
@@ -1,37 +0,0 @@
|
||||
fastlane documentation
|
||||
================
|
||||
# Installation
|
||||
|
||||
Make sure you have the latest version of the Xcode command line tools installed:
|
||||
|
||||
```
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
Install _fastlane_ using
|
||||
```
|
||||
[sudo] gem install fastlane -NV
|
||||
```
|
||||
or alternatively using `brew install fastlane`
|
||||
|
||||
# Available Actions
|
||||
### match_me
|
||||
```
|
||||
fastlane match_me
|
||||
```
|
||||
Installs all Certs and Profiles necessary for development and ad-hoc
|
||||
|
||||
----
|
||||
|
||||
## iOS
|
||||
### ios deploy_to_firebase
|
||||
```
|
||||
fastlane ios deploy_to_firebase
|
||||
```
|
||||
Deploy build to Firebase
|
||||
|
||||
----
|
||||
|
||||
This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
|
||||
More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
|
||||
The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>iCloudContainerEnvironment</key>
|
||||
<string>Development</string>
|
||||
<key>provisioningProfiles</key>
|
||||
<dict>
|
||||
<key>io.getstream.flutter</key>
|
||||
<string>match AdHoc io.getstream.flutter</string>
|
||||
<key>io.getstream.flutter.Notifications</key>
|
||||
<string>match AdHoc io.getstream.flutter.Notifications</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites>
|
||||
<testsuite name="fastlane.lanes">
|
||||
|
||||
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="0: Verifying fastlane version" time="0.000371">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="1: default_platform" time="0.000177">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="2: is_ci" time="0.000187">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="3: is_ci" time="0.000166">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="4: match" time="36.640008">
|
||||
|
||||
</testcase>
|
||||
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
@@ -1,328 +0,0 @@
|
||||
import 'package:example/routes/routes.dart';
|
||||
import 'package:example/stream_version.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
import 'choose_user_page.dart';
|
||||
import 'main.dart';
|
||||
|
||||
class AdvancedOptionsPage extends StatefulWidget {
|
||||
@override
|
||||
_AdvancedOptionsPageState createState() => _AdvancedOptionsPageState();
|
||||
}
|
||||
|
||||
class _AdvancedOptionsPageState extends State<AdvancedOptionsPage> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
final TextEditingController _apiKeyController = TextEditingController();
|
||||
String _apiKeyError;
|
||||
|
||||
final TextEditingController _userIdController = TextEditingController();
|
||||
String _userIdError;
|
||||
|
||||
final TextEditingController _userTokenController = TextEditingController();
|
||||
String _userTokenError;
|
||||
|
||||
final TextEditingController _usernameController = TextEditingController();
|
||||
|
||||
bool loading = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
resizeToAvoidBottomPadding: false,
|
||||
appBar: AppBar(
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||
elevation: 1,
|
||||
centerTitle: true,
|
||||
brightness: Theme.of(context).brightness,
|
||||
title: Text(
|
||||
'Advanced Options',
|
||||
style: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.headlineBold
|
||||
.copyWith(color: StreamChatTheme.of(context).colorTheme.black),
|
||||
),
|
||||
leading: IconButton(
|
||||
icon: StreamSvgIcon.left(
|
||||
color: StreamChatTheme.of(context).colorTheme.black,
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
),
|
||||
body: Builder(
|
||||
builder: (context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: _apiKeyController,
|
||||
onChanged: (_) {
|
||||
if (_apiKeyError != null) {
|
||||
setState(() {
|
||||
_apiKeyError = null;
|
||||
});
|
||||
}
|
||||
},
|
||||
validator: (value) {
|
||||
if (value.isEmpty) {
|
||||
setState(() {
|
||||
_apiKeyError = 'Please enter the Chat API Key';
|
||||
});
|
||||
return _apiKeyError;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: StreamChatTheme.of(context).colorTheme.black,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
errorStyle: TextStyle(height: 0, fontSize: 0),
|
||||
labelStyle: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _apiKeyError != null
|
||||
? StreamChatTheme.of(context).colorTheme.accentRed
|
||||
: StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
border: UnderlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
fillColor:
|
||||
StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||
filled: true,
|
||||
labelText:
|
||||
'Chat API Key ${_apiKeyError != null ? ': $_apiKeyError' : ''}',
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
TextFormField(
|
||||
controller: _userIdController,
|
||||
onChanged: (_) {
|
||||
if (_userIdError != null) {
|
||||
setState(() {
|
||||
_userIdError = null;
|
||||
});
|
||||
}
|
||||
},
|
||||
validator: (value) {
|
||||
if (value.isEmpty) {
|
||||
setState(() {
|
||||
_userIdError = 'Please enter the User ID';
|
||||
});
|
||||
return _userIdError;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: StreamChatTheme.of(context).colorTheme.black,
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
decoration: InputDecoration(
|
||||
errorStyle: TextStyle(height: 0, fontSize: 0),
|
||||
labelStyle: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
color: _userIdError != null
|
||||
? StreamChatTheme.of(context).colorTheme.accentRed
|
||||
: StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
border: UnderlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
fillColor:
|
||||
StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||
filled: true,
|
||||
labelText:
|
||||
'User ID ${_userIdError != null ? ': $_userIdError' : ''}',
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
TextFormField(
|
||||
onChanged: (_) {
|
||||
if (_userTokenError != null) {
|
||||
setState(() {
|
||||
_userTokenError = null;
|
||||
});
|
||||
}
|
||||
},
|
||||
controller: _userTokenController,
|
||||
validator: (value) {
|
||||
if (value.isEmpty) {
|
||||
setState(() {
|
||||
_userTokenError = 'Please enter the user token';
|
||||
});
|
||||
return _userTokenError;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: StreamChatTheme.of(context).colorTheme.black,
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
decoration: InputDecoration(
|
||||
errorStyle: TextStyle(height: 0, fontSize: 0),
|
||||
labelStyle: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
color: _userTokenError != null
|
||||
? StreamChatTheme.of(context).colorTheme.accentRed
|
||||
: StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
border: UnderlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
fillColor:
|
||||
StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||
filled: true,
|
||||
labelText:
|
||||
'User Token ${_userTokenError != null ? ': $_userTokenError' : ''}',
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
TextFormField(
|
||||
controller: _usernameController,
|
||||
textInputAction: TextInputAction.done,
|
||||
decoration: InputDecoration(
|
||||
labelStyle: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
border: UnderlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
fillColor:
|
||||
StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||
filled: true,
|
||||
labelText: 'Username (optional)',
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
RaisedButton(
|
||||
color: Theme.of(context).brightness == Brightness.light
|
||||
? StreamChatTheme.of(context).colorTheme.accentBlue
|
||||
: Colors.white,
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(26),
|
||||
),
|
||||
child: Text(
|
||||
'Login',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context).brightness != Brightness.light
|
||||
? StreamChatTheme.of(context).colorTheme.accentBlue
|
||||
: Colors.white,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
if (_formKey.currentState.validate()) {
|
||||
final apiKey = _apiKeyController.text;
|
||||
final userId = _userIdController.text;
|
||||
final userToken = _userTokenController.text;
|
||||
final username = _usernameController.text;
|
||||
|
||||
loading = true;
|
||||
showDialog(
|
||||
barrierDismissible: false,
|
||||
context: context,
|
||||
barrierColor:
|
||||
StreamChatTheme.of(context).colorTheme.overlay,
|
||||
builder: (context) => Center(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.white,
|
||||
),
|
||||
height: 100,
|
||||
width: 100,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final client = StreamChatClient(
|
||||
apiKey,
|
||||
logLevel: Level.INFO,
|
||||
)..chatPersistenceClient = chatPersistentClient;
|
||||
|
||||
try {
|
||||
await client.setUser(
|
||||
User(id: userId, extraData: {
|
||||
'name': username,
|
||||
}),
|
||||
userToken,
|
||||
);
|
||||
|
||||
final secureStorage = FlutterSecureStorage();
|
||||
secureStorage.write(
|
||||
key: kStreamApiKey,
|
||||
value: apiKey,
|
||||
);
|
||||
secureStorage.write(
|
||||
key: kStreamUserId,
|
||||
value: userId,
|
||||
);
|
||||
secureStorage.write(
|
||||
key: kStreamToken,
|
||||
value: userToken,
|
||||
);
|
||||
} catch (e) {
|
||||
var errorText = 'Error connecting, retry';
|
||||
if (e is Map) {
|
||||
errorText = e['message'] ?? errorText;
|
||||
}
|
||||
Navigator.pop(context);
|
||||
setState(() {
|
||||
_apiKeyError = errorText;
|
||||
});
|
||||
loading = false;
|
||||
await client.disconnect();
|
||||
return;
|
||||
}
|
||||
loading = false;
|
||||
await Navigator.pushNamedAndRemoveUntil(
|
||||
context,
|
||||
Routes.APP,
|
||||
ModalRoute.withName(Routes.APP),
|
||||
arguments: client,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
StreamVersion(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,600 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:jiffy/jiffy.dart';
|
||||
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
import 'main.dart';
|
||||
import 'routes/routes.dart';
|
||||
|
||||
/// Detail screen for a 1:1 chat correspondence
|
||||
class ChatInfoScreen extends StatefulWidget {
|
||||
/// User in consideration
|
||||
final User user;
|
||||
|
||||
const ChatInfoScreen({Key key, this.user}) : super(key: key);
|
||||
|
||||
@override
|
||||
_ChatInfoScreenState createState() => _ChatInfoScreenState();
|
||||
}
|
||||
|
||||
class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final channel = StreamChannel.of(context).channel;
|
||||
return Scaffold(
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
body: ListView(
|
||||
children: [
|
||||
_buildUserHeader(),
|
||||
Container(
|
||||
height: 8.0,
|
||||
color: StreamChatTheme.of(context).colorTheme.greyGainsboro,
|
||||
),
|
||||
_buildOptionListTiles(),
|
||||
Container(
|
||||
height: 8.0,
|
||||
color: StreamChatTheme.of(context).colorTheme.greyGainsboro,
|
||||
),
|
||||
if ([
|
||||
'admin',
|
||||
'owner',
|
||||
].contains(channel.state.members
|
||||
.firstWhere((m) => m.userId == channel.client.state.user.id,
|
||||
orElse: () => null)
|
||||
?.role))
|
||||
_buildDeleteListTile(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildUserHeader() {
|
||||
return Material(
|
||||
color: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
child: SafeArea(
|
||||
child: Stack(
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: UserAvatar(
|
||||
user: widget.user,
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: 72.0,
|
||||
maxHeight: 72.0,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(36.0),
|
||||
showOnlineStatus: false,
|
||||
),
|
||||
),
|
||||
//SizedBox(height: 4.0),
|
||||
Text(
|
||||
widget.user.name,
|
||||
style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 7.0),
|
||||
_buildConnectedTitleState(),
|
||||
SizedBox(height: 15.0),
|
||||
OptionListTile(
|
||||
title: '@${widget.user.id}',
|
||||
tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
trailing: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Text(
|
||||
widget.user.name,
|
||||
style: TextStyle(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(0.5),
|
||||
fontSize: 16.0),
|
||||
),
|
||||
),
|
||||
onTap: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
Positioned(
|
||||
top: 21,
|
||||
left: 16,
|
||||
child: InkWell(
|
||||
child: StreamSvgIcon.left(
|
||||
color: StreamChatTheme.of(context).colorTheme.black,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildOptionListTiles() {
|
||||
var channel = StreamChannel.of(context);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
// _OptionListTile(
|
||||
// title: 'Notifications',
|
||||
// leading: StreamSvgIcon.Icon_notification(
|
||||
// size: 24.0,
|
||||
// color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5),
|
||||
// ),
|
||||
// trailing: CupertinoSwitch(
|
||||
// value: true,
|
||||
// onChanged: (val) {},
|
||||
// ),
|
||||
// onTap: () {},
|
||||
// ),
|
||||
StreamBuilder<bool>(
|
||||
stream: StreamChannel.of(context).channel.isMutedStream,
|
||||
builder: (context, snapshot) {
|
||||
return OptionListTile(
|
||||
tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
title: 'Mute user',
|
||||
titleTextStyle: StreamChatTheme.of(context).textTheme.body,
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 22.0),
|
||||
child: StreamSvgIcon.mute(
|
||||
size: 24.0,
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(0.5),
|
||||
),
|
||||
),
|
||||
trailing: snapshot.data == null
|
||||
? CircularProgressIndicator()
|
||||
: CupertinoSwitch(
|
||||
value: snapshot.data,
|
||||
onChanged: (val) {
|
||||
if (snapshot.data) {
|
||||
channel.channel.unmute();
|
||||
} else {
|
||||
channel.channel.mute();
|
||||
}
|
||||
},
|
||||
),
|
||||
onTap: () {},
|
||||
);
|
||||
}),
|
||||
// _OptionListTile(
|
||||
// title: 'Block User',
|
||||
// leading: StreamSvgIcon.Icon_user_delete(
|
||||
// size: 24.0,
|
||||
// color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5),
|
||||
// ),
|
||||
// trailing: CupertinoSwitch(
|
||||
// value: widget.user.banned,
|
||||
// onChanged: (val) {
|
||||
// if (widget.user.banned) {
|
||||
// channel.channel.shadowBan(widget.user.id, {});
|
||||
// } else {
|
||||
// channel.channel.unbanUser(widget.user.id);
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// onTap: () {},
|
||||
// ),
|
||||
OptionListTile(
|
||||
title: 'Photos & Videos',
|
||||
tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
titleTextStyle: StreamChatTheme.of(context).textTheme.body,
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: StreamSvgIcon.pictures(
|
||||
size: 36.0,
|
||||
color:
|
||||
StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5),
|
||||
),
|
||||
),
|
||||
trailing: StreamSvgIcon.right(
|
||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
onTap: () {
|
||||
final channel = StreamChannel.of(context).channel;
|
||||
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => StreamChannel(
|
||||
channel: channel,
|
||||
child: MessageSearchBloc(
|
||||
child: ChannelMediaDisplayScreen(
|
||||
sortOptions: [
|
||||
SortOption(
|
||||
'created_at',
|
||||
direction: SortOption.ASC,
|
||||
),
|
||||
],
|
||||
paginationParams: PaginationParams(limit: 20),
|
||||
onShowMessage: (m, c) async {
|
||||
final client = StreamChat.of(context).client;
|
||||
final message = m;
|
||||
final channel = client.channel(
|
||||
c.type,
|
||||
id: c.id,
|
||||
);
|
||||
if (channel.state == null) {
|
||||
await channel.watch();
|
||||
}
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
Routes.CHANNEL_PAGE,
|
||||
arguments: ChannelPageArgs(
|
||||
channel: channel,
|
||||
initialMessage: message,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
OptionListTile(
|
||||
title: 'Files',
|
||||
tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
titleTextStyle: StreamChatTheme.of(context).textTheme.body,
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0),
|
||||
child: StreamSvgIcon.files(
|
||||
size: 32.0,
|
||||
color:
|
||||
StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5),
|
||||
),
|
||||
),
|
||||
trailing: StreamSvgIcon.right(
|
||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
onTap: () {
|
||||
final channel = StreamChannel.of(context).channel;
|
||||
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => StreamChannel(
|
||||
channel: channel,
|
||||
child: MessageSearchBloc(
|
||||
child: ChannelFileDisplayScreen(
|
||||
sortOptions: [
|
||||
SortOption(
|
||||
'created_at',
|
||||
direction: SortOption.ASC,
|
||||
),
|
||||
],
|
||||
paginationParams: PaginationParams(limit: 20),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
OptionListTile(
|
||||
title: 'Shared groups',
|
||||
tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
titleTextStyle: StreamChatTheme.of(context).textTheme.body,
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 22.0),
|
||||
child: StreamSvgIcon.Icon_group(
|
||||
size: 24.0,
|
||||
color:
|
||||
StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5),
|
||||
),
|
||||
),
|
||||
trailing: StreamSvgIcon.right(
|
||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => _SharedGroupsScreen(
|
||||
StreamChat.of(context).user, widget.user)));
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDeleteListTile() {
|
||||
return OptionListTile(
|
||||
title: 'Delete Conversation',
|
||||
tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
titleTextStyle: StreamChatTheme.of(context).textTheme.body.copyWith(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentRed,
|
||||
),
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 22.0),
|
||||
child: StreamSvgIcon.delete(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentRed,
|
||||
size: 24.0,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
_showDeleteDialog();
|
||||
},
|
||||
titleColor: StreamChatTheme.of(context).colorTheme.accentRed,
|
||||
);
|
||||
}
|
||||
|
||||
void _showDeleteDialog() async {
|
||||
final res = await showConfirmationDialog(
|
||||
context,
|
||||
title: 'Delete Conversation',
|
||||
okText: 'DELETE',
|
||||
question: 'Are you sure you want to delete this conversation?',
|
||||
cancelText: 'CANCEL',
|
||||
icon: StreamSvgIcon.delete(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentRed,
|
||||
),
|
||||
);
|
||||
var channel = StreamChannel.of(context).channel;
|
||||
if (res == true) {
|
||||
await channel.delete().then((value) {
|
||||
Navigator.pop(context);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildConnectedTitleState() {
|
||||
var alternativeWidget;
|
||||
|
||||
final otherMember = widget.user;
|
||||
|
||||
if (otherMember != null) {
|
||||
if (otherMember.online) {
|
||||
alternativeWidget = Text(
|
||||
'Online',
|
||||
style: TextStyle(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(0.5)),
|
||||
);
|
||||
} else {
|
||||
alternativeWidget = Text(
|
||||
'Last seen ${Jiffy(otherMember.lastActive).fromNow()}',
|
||||
style: TextStyle(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(0.5)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (widget.user.online)
|
||||
Material(
|
||||
type: MaterialType.circle,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
constraints: BoxConstraints.tightFor(
|
||||
width: 24,
|
||||
height: 12,
|
||||
),
|
||||
child: Material(
|
||||
shape: CircleBorder(),
|
||||
color: StreamChatTheme.of(context).colorTheme.accentGreen,
|
||||
),
|
||||
),
|
||||
color: StreamChatTheme.of(context).colorTheme.white,
|
||||
),
|
||||
alternativeWidget,
|
||||
if (widget.user.online)
|
||||
SizedBox(
|
||||
width: 24.0,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SharedGroupsScreen extends StatefulWidget {
|
||||
final User mainUser;
|
||||
final User otherUser;
|
||||
|
||||
_SharedGroupsScreen(this.mainUser, this.otherUser);
|
||||
|
||||
@override
|
||||
__SharedGroupsScreenState createState() => __SharedGroupsScreenState();
|
||||
}
|
||||
|
||||
class __SharedGroupsScreenState extends State<_SharedGroupsScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var chat = StreamChat.of(context);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
appBar: AppBar(
|
||||
brightness: Theme.of(context).brightness,
|
||||
elevation: 1,
|
||||
centerTitle: true,
|
||||
title: Text(
|
||||
'Shared Groups',
|
||||
style: TextStyle(
|
||||
color: StreamChatTheme.of(context).colorTheme.black,
|
||||
fontSize: 16.0),
|
||||
),
|
||||
leading: Center(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Container(
|
||||
child: StreamSvgIcon.left(
|
||||
color: StreamChatTheme.of(context).colorTheme.black,
|
||||
size: 24.0,
|
||||
),
|
||||
width: 24.0,
|
||||
height: 24.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||
),
|
||||
body: FutureBuilder<List<Channel>>(
|
||||
future: chat.client.queryChannels(
|
||||
filter: {
|
||||
r'$and': [
|
||||
{
|
||||
'members': {
|
||||
r'$in': [widget.otherUser.id],
|
||||
},
|
||||
},
|
||||
{
|
||||
'members': {
|
||||
r'$in': [widget.mainUser.id],
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
if (snapshot.data.isEmpty) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
StreamSvgIcon.message(
|
||||
size: 136.0,
|
||||
color: StreamChatTheme.of(context).colorTheme.greyGainsboro,
|
||||
),
|
||||
SizedBox(height: 16.0),
|
||||
Text(
|
||||
'No Shared Groups',
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
color: StreamChatTheme.of(context).colorTheme.black,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8.0),
|
||||
Text(
|
||||
'Group shared with User will appear here.',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(0.5),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: snapshot.data.length,
|
||||
itemBuilder: (context, position) {
|
||||
return StreamChannel(
|
||||
channel: snapshot.data[position],
|
||||
child: _buildListTile(snapshot.data[position]),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildListTile(Channel channel) {
|
||||
var extraData = channel.extraData;
|
||||
var members = channel.state.members;
|
||||
|
||||
var textStyle = TextStyle(fontSize: 14.0, fontWeight: FontWeight.bold);
|
||||
|
||||
return Container(
|
||||
height: 64.0,
|
||||
child: LayoutBuilder(builder: (context, constraints) {
|
||||
String title;
|
||||
if (extraData['name'] == null) {
|
||||
final otherMembers = members.where(
|
||||
(member) => member.userId != StreamChat.of(context).user.id);
|
||||
if (otherMembers.isNotEmpty) {
|
||||
final maxWidth = constraints.maxWidth;
|
||||
final maxChars = maxWidth / textStyle.fontSize;
|
||||
var currentChars = 0;
|
||||
final currentMembers = <Member>[];
|
||||
otherMembers.forEach((element) {
|
||||
final newLength = currentChars + element.user.name.length;
|
||||
if (newLength < maxChars) {
|
||||
currentChars = newLength;
|
||||
currentMembers.add(element);
|
||||
}
|
||||
});
|
||||
|
||||
final exceedingMembers =
|
||||
otherMembers.length - currentMembers.length;
|
||||
title =
|
||||
'${currentMembers.map((e) => e.user.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}';
|
||||
} else {
|
||||
title = 'No title';
|
||||
}
|
||||
} else {
|
||||
title = extraData['name'];
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: ChannelImage(
|
||||
channel: channel,
|
||||
constraints:
|
||||
BoxConstraints(maxWidth: 40.0, maxHeight: 40.0),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: textStyle,
|
||||
)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'${channel.memberCount} members',
|
||||
style: TextStyle(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(0.5)),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 1.0,
|
||||
color:
|
||||
StreamChatTheme.of(context).colorTheme.black.withOpacity(.08),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
typedef ChipBuilder<T> = Widget Function(BuildContext context, T chip);
|
||||
typedef OnChipAdded<T> = void Function(T chip);
|
||||
typedef OnChipRemoved<T> = void Function(T chip);
|
||||
|
||||
class ChipsInputTextField<T> extends StatefulWidget {
|
||||
final TextEditingController controller;
|
||||
final FocusNode focusNode;
|
||||
final ValueChanged<String> onInputChanged;
|
||||
final ChipBuilder<T> chipBuilder;
|
||||
final OnChipAdded<T> onChipAdded;
|
||||
final OnChipRemoved<T> onChipRemoved;
|
||||
final String hint;
|
||||
|
||||
const ChipsInputTextField({
|
||||
Key key,
|
||||
@required this.chipBuilder,
|
||||
@required this.controller,
|
||||
this.onInputChanged,
|
||||
this.focusNode,
|
||||
this.onChipAdded,
|
||||
this.onChipRemoved,
|
||||
this.hint = 'Type a name',
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
ChipInputTextFieldState<T> createState() => ChipInputTextFieldState<T>();
|
||||
}
|
||||
|
||||
class ChipInputTextFieldState<T> extends State<ChipsInputTextField<T>> {
|
||||
final _chips = <T>{};
|
||||
bool _pauseItemAddition = false;
|
||||
|
||||
void addItem(T item) {
|
||||
setState(() => _chips.add(item));
|
||||
if (widget.onChipAdded != null) widget.onChipAdded(item);
|
||||
}
|
||||
|
||||
void removeItem(T item) {
|
||||
setState(() {
|
||||
_chips.remove(item);
|
||||
if (_chips.isEmpty) resumeItemAddition();
|
||||
});
|
||||
if (widget.onChipRemoved != null) widget.onChipRemoved(item);
|
||||
}
|
||||
|
||||
void pauseItemAddition() {
|
||||
if (!_pauseItemAddition) {
|
||||
setState(() => _pauseItemAddition = true);
|
||||
}
|
||||
widget.focusNode?.unfocus();
|
||||
}
|
||||
|
||||
void resumeItemAddition() {
|
||||
if (_pauseItemAddition) {
|
||||
setState(() => _pauseItemAddition = false);
|
||||
}
|
||||
widget.focusNode?.requestFocus();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: _pauseItemAddition ? resumeItemAddition : null,
|
||||
child: Material(
|
||||
elevation: 1,
|
||||
color: StreamChatTheme.of(context).colorTheme.white,
|
||||
child: Container(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 16),
|
||||
child: IntrinsicHeight(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||
child: Text(
|
||||
'TO:',
|
||||
style: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.footnote
|
||||
.copyWith(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(.5)),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Wrap(
|
||||
spacing: 8.0,
|
||||
runSpacing: 4.0,
|
||||
children: _chips.map((item) {
|
||||
return widget.chipBuilder(context, item);
|
||||
}).toList(),
|
||||
),
|
||||
if (!_pauseItemAddition)
|
||||
TextField(
|
||||
controller: widget.controller,
|
||||
onChanged: widget.onInputChanged,
|
||||
focusNode: widget.focusNode,
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
errorBorder: InputBorder.none,
|
||||
disabledBorder: InputBorder.none,
|
||||
contentPadding: const EdgeInsets.only(top: 4.0),
|
||||
hintText: widget.hint,
|
||||
hintStyle: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.body
|
||||
.copyWith(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(.5)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: IconButton(
|
||||
icon: _chips.isEmpty
|
||||
? StreamSvgIcon.user(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(0.5),
|
||||
size: 24,
|
||||
)
|
||||
: StreamSvgIcon.userAdd(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(0.5),
|
||||
size: 24,
|
||||
),
|
||||
onPressed: resumeItemAddition,
|
||||
alignment: Alignment.topRight,
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: const EdgeInsets.all(0),
|
||||
splashRadius: 24,
|
||||
constraints: BoxConstraints.tightFor(
|
||||
height: 24,
|
||||
width: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
import 'package:example/stream_version.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
import 'routes/routes.dart';
|
||||
|
||||
const kStreamApiKey = 'STREAM_API_KEY';
|
||||
const kStreamUserId = 'STREAM_USER_ID';
|
||||
const kStreamToken = 'STREAM_TOKEN';
|
||||
const kDefaultStreamApiKey = 'kv7mcsxr24p8';
|
||||
|
||||
class ChooseUserPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final users = <String, User>{
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoic2FsdmF0b3JlIn0.pgiJz7sIc7iP29BHKFwe3nLm5-OaR_1l2P-SlgiC9a8':
|
||||
User(
|
||||
id: 'salvatore',
|
||||
extraData: {
|
||||
'name': 'Salvatore Giordano',
|
||||
'image':
|
||||
'https://ca.slack-edge.com/T02RM6X6B-USKK9FFRT-30c415e207a9-512',
|
||||
},
|
||||
),
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoic2FoaWwifQ.WnIUoB5gR2kcAsFhiDvkiD6zdHXZ-VSU2aQWWkhsvfo':
|
||||
User(
|
||||
id: 'sahil',
|
||||
extraData: {
|
||||
'name': 'Sahil Kumar',
|
||||
'image':
|
||||
'https://ca.slack-edge.com/T02RM6X6B-U01EYU51M89-bbc152b40321-512',
|
||||
},
|
||||
),
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiYmVuIn0.nAz2sNFGQwY7rl2Og2z3TGHUsdpnN53tOsUglJFvLmg':
|
||||
User(
|
||||
id: 'ben',
|
||||
extraData: {
|
||||
'name': 'Ben Golden',
|
||||
'image':
|
||||
'https://ca.slack-edge.com/T02RM6X6B-U01AXAF23MG-f57403a3cb0d-512',
|
||||
},
|
||||
),
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidGhpZXJyeSJ9.lEq6TrZtHzjoNtf7HHRufUPyGo_pa8vg4_XhEBp4ckY':
|
||||
User(
|
||||
id: 'thierry',
|
||||
extraData: {
|
||||
'name': 'Thierry Schellenbach',
|
||||
'image':
|
||||
'https://ca.slack-edge.com/T02RM6X6B-U02RM6X6D-g28a1278a98e-512',
|
||||
},
|
||||
),
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidG9tbWFzbyJ9.GLSI0ESshERMo2WjUpysD709NEtn1zmGimUN2an7g9o':
|
||||
User(
|
||||
id: 'tommaso',
|
||||
extraData: {
|
||||
'name': 'Tommaso Barbugli',
|
||||
'image':
|
||||
'https://ca.slack-edge.com/T02RM6X6B-U02U7SJP4-0f65a5997877-512',
|
||||
},
|
||||
),
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiZGV2ZW4ifQ.z3zI4PqJnNhc-1o-VKcmb6BnnQ0oxFNCRHwEulHqcWc':
|
||||
User(
|
||||
id: 'deven',
|
||||
extraData: {
|
||||
'name': 'Deven Joshi',
|
||||
'image':
|
||||
'https://ca.slack-edge.com/T02RM6X6B-U01AM7ELPTL-8a60da32704c-512',
|
||||
},
|
||||
),
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoibmVldmFzaCJ9.3EdHegTxibrz3A9cTiKmpEyawwcCVB8FXnoFzr4eKvw':
|
||||
User(
|
||||
id: 'neevash',
|
||||
extraData: {
|
||||
'name': 'Neevash Ramdial',
|
||||
'image':
|
||||
'https://ca.slack-edge.com/T02RM6X6B-U01DZ046DS8-b00d321d2880-512',
|
||||
},
|
||||
),
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoicWF0ZXN0MSJ9.fnelU7HcP7QoEEsCGteNlF1fppofzNlrnpDQuIgeKCU':
|
||||
User(
|
||||
id: 'qatest1',
|
||||
extraData: {
|
||||
'name': 'QA test 1',
|
||||
},
|
||||
),
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoicWF0ZXN0MiJ9.vSCqAEbs2WVmMWsOsa7065Fsjq-rsTih6qsHPynl7XM':
|
||||
User(
|
||||
id: 'qatest2',
|
||||
extraData: {
|
||||
'name': 'QA test 2',
|
||||
},
|
||||
),
|
||||
};
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 34,
|
||||
bottom: 20,
|
||||
),
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
'assets/logo.svg',
|
||||
height: 40,
|
||||
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 13.0),
|
||||
child: Text(
|
||||
'Welcome to Stream Chat',
|
||||
style: StreamChatTheme.of(context).textTheme.title,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'Select a user to try the Flutter SDK:',
|
||||
style: StreamChatTheme.of(context).textTheme.body,
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 32),
|
||||
child: ListView.separated(
|
||||
separatorBuilder: (context, i) {
|
||||
return Container(
|
||||
height: 1,
|
||||
color: StreamChatTheme.of(context).colorTheme.greyWhisper,
|
||||
);
|
||||
},
|
||||
itemCount: users.length + 1,
|
||||
itemBuilder: (context, i) {
|
||||
return [
|
||||
...users.entries.map((entry) {
|
||||
final token = entry.key;
|
||||
final user = entry.value;
|
||||
return ListTile(
|
||||
onTap: () async {
|
||||
showDialog(
|
||||
barrierDismissible: false,
|
||||
context: context,
|
||||
barrierColor: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.overlay,
|
||||
builder: (context) => Center(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.white,
|
||||
),
|
||||
height: 100,
|
||||
width: 100,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final secureStorage = FlutterSecureStorage();
|
||||
final client = StreamChat.of(context).client;
|
||||
client.apiKey = kDefaultStreamApiKey;
|
||||
await client.setUser(
|
||||
user,
|
||||
token,
|
||||
);
|
||||
|
||||
secureStorage.write(
|
||||
key: kStreamApiKey,
|
||||
value: kDefaultStreamApiKey,
|
||||
);
|
||||
secureStorage.write(
|
||||
key: kStreamUserId,
|
||||
value: user.id,
|
||||
);
|
||||
secureStorage.write(
|
||||
key: kStreamToken,
|
||||
value: token,
|
||||
);
|
||||
Navigator.pushNamedAndRemoveUntil(
|
||||
context,
|
||||
Routes.HOME,
|
||||
ModalRoute.withName(Routes.HOME),
|
||||
);
|
||||
},
|
||||
leading: UserAvatar(
|
||||
user: user,
|
||||
constraints: BoxConstraints.tight(
|
||||
Size.fromRadius(20),
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
user.name,
|
||||
style:
|
||||
StreamChatTheme.of(context).textTheme.bodyBold,
|
||||
),
|
||||
subtitle: Text(
|
||||
'Stream test account',
|
||||
style: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.footnote
|
||||
.copyWith(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.grey,
|
||||
),
|
||||
),
|
||||
trailing: StreamSvgIcon.arrow_right(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.accentBlue,
|
||||
),
|
||||
);
|
||||
}),
|
||||
ListTile(
|
||||
onTap: () {
|
||||
Navigator.pushNamed(context, Routes.ADVANCED_OPTIONS);
|
||||
},
|
||||
leading: CircleAvatar(
|
||||
child: StreamSvgIcon.settings(
|
||||
color: StreamChatTheme.of(context).colorTheme.black,
|
||||
),
|
||||
backgroundColor: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.greyWhisper,
|
||||
),
|
||||
title: Text(
|
||||
'Advanced Options',
|
||||
style: StreamChatTheme.of(context).textTheme.bodyBold,
|
||||
),
|
||||
subtitle: Text(
|
||||
'Custom settings',
|
||||
style: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.footnote
|
||||
.copyWith(
|
||||
color:
|
||||
StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
),
|
||||
trailing: SvgPicture.asset(
|
||||
'assets/icon_arrow_right.svg',
|
||||
height: 24,
|
||||
width: 24,
|
||||
clipBehavior: Clip.none,
|
||||
),
|
||||
),
|
||||
][i];
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
StreamVersion(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
/// Fifth step of the [tutorial](https://getstream.io/chat/flutter/tutorial/)
|
||||
///
|
||||
/// Customizing how messages are rendered is another very common use-case that the SDK supports easily.
|
||||
///
|
||||
/// Replace the built-in message component with your own is done by passing it as a builder function to the [MessageListView] widget.
|
||||
///
|
||||
/// The message builder function will get the usual [BuildContext] argument as well as the [Message] object and its position inside the list.
|
||||
///
|
||||
/// If you look at the code you can see that we use [StreamChat.of] to retrieve the current user so that we can style messages own messages in a different way.
|
||||
///
|
||||
/// Since custom widgets and builders are always children of [StreamChat] or part of a [Channel],
|
||||
/// you can use [StreamChat.of], [StreamChannel.of] and [StreamChatTheme.of] to use the API client directly
|
||||
/// or to retrieve outer scope needed such as messages from the [Channel.state].
|
||||
void main() async {
|
||||
final client = StreamChatClient(
|
||||
's2dxdhpxd94g',
|
||||
logLevel: Level.INFO,
|
||||
);
|
||||
|
||||
await client.setUser(
|
||||
User(id: 'super-band-9'),
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
|
||||
);
|
||||
|
||||
runApp(MyApp(client));
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
final StreamChatClient client;
|
||||
|
||||
MyApp(this.client);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
builder: (context, child) => StreamChat(
|
||||
child: child,
|
||||
client: client,
|
||||
),
|
||||
home: ChannelListPage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelListPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: ChannelsBloc(
|
||||
child: ChannelListView(
|
||||
filter: {
|
||||
'members': {
|
||||
'\$in': [StreamChat.of(context).user.id],
|
||||
}
|
||||
},
|
||||
sort: [SortOption('last_message_at')],
|
||||
pagination: PaginationParams(
|
||||
limit: 20,
|
||||
),
|
||||
channelWidget: ChannelPage(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelPage extends StatelessWidget {
|
||||
const ChannelPage({
|
||||
Key key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: ChannelHeader(),
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: MessageListView(
|
||||
messageBuilder: _messageBuilder,
|
||||
),
|
||||
),
|
||||
MessageInput(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _messageBuilder(
|
||||
BuildContext context,
|
||||
MessageDetails details,
|
||||
List<Message> messages,
|
||||
) {
|
||||
final message = details.message;
|
||||
final isCurrentUser = StreamChat.of(context).user.id == message.user.id;
|
||||
final textAlign = isCurrentUser ? TextAlign.right : TextAlign.left;
|
||||
final color = isCurrentUser ? Colors.blueGrey : Colors.blue;
|
||||
|
||||
return Padding(
|
||||
padding: EdgeInsets.all(5.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: color, width: 1),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(5.0),
|
||||
),
|
||||
),
|
||||
child: ListTile(
|
||||
title: Text(
|
||||
message.text,
|
||||
textAlign: textAlign,
|
||||
),
|
||||
subtitle: Text(
|
||||
message.user.extraData['name'],
|
||||
textAlign: textAlign,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
/// Sixth step of the [tutorial](https://getstream.io/chat/flutter/tutorial/)
|
||||
///
|
||||
/// The Flutter SDK comes with a fully designed set of widgets which you can customize to fit with your application style and typography.
|
||||
/// Changing the theme of Chat widgets works in a very similar way that [MaterialApp] and [Theme] do.
|
||||
///
|
||||
/// Out of the box all chat widgets use their own default styling, there are two ways to change the styling:
|
||||
///
|
||||
/// 1. Initialize the [StreamChatTheme] from your existing [MaterialApp] style
|
||||
/// 2. Construct a custom theme and provide all the customizations needed
|
||||
///
|
||||
/// First we create a new Material [Theme] and pick [Colors.green] as swatch color. The theme is then passed to [MaterialApp] as usual.
|
||||
///
|
||||
/// Then we create a new [StreamChatTheme] from the green theme we just created.
|
||||
/// After saving the app you will see the UI will update several widgets to match with the new color.
|
||||
///
|
||||
/// We also change the message color posted by the current user.
|
||||
/// You can perform these more granular style changes using [StreamChatTheme.copyWith].
|
||||
void main() async {
|
||||
final client = StreamChatClient(
|
||||
's2dxdhpxd94g',
|
||||
logLevel: Level.INFO,
|
||||
);
|
||||
|
||||
await client.setUser(
|
||||
User(id: 'super-band-9'),
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
|
||||
);
|
||||
|
||||
runApp(MyApp(client));
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
final StreamChatClient client;
|
||||
|
||||
MyApp(this.client);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final themeData = ThemeData(primarySwatch: Colors.green);
|
||||
final defaultTheme = StreamChatThemeData.fromTheme(themeData);
|
||||
final colorTheme = defaultTheme.colorTheme;
|
||||
final customTheme = defaultTheme.merge(StreamChatThemeData(
|
||||
ownMessageTheme: MessageTheme(
|
||||
messageBackgroundColor: colorTheme.black,
|
||||
messageText: TextStyle(
|
||||
color: colorTheme.white,
|
||||
),
|
||||
avatarTheme: AvatarTheme(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
return MaterialApp(
|
||||
theme: themeData,
|
||||
builder: (context, child) {
|
||||
return StreamChat(
|
||||
child: child,
|
||||
client: client,
|
||||
streamChatThemeData: customTheme,
|
||||
);
|
||||
},
|
||||
home: ChannelListPage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelListPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: ChannelsBloc(
|
||||
child: ChannelListView(
|
||||
filter: {
|
||||
'members': {
|
||||
'\$in': [StreamChat.of(context).user.id],
|
||||
}
|
||||
},
|
||||
sort: [SortOption('last_message_at')],
|
||||
pagination: PaginationParams(
|
||||
limit: 20,
|
||||
),
|
||||
channelWidget: ChannelPage(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelPage extends StatelessWidget {
|
||||
const ChannelPage({
|
||||
Key key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: ChannelHeader(),
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: MessageListView(
|
||||
threadBuilder: (_, parentMessage) {
|
||||
return ThreadPage(
|
||||
parent: parentMessage,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
MessageInput(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ThreadPage extends StatelessWidget {
|
||||
final Message parent;
|
||||
|
||||
ThreadPage({
|
||||
Key key,
|
||||
this.parent,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: ThreadHeader(
|
||||
parent: parent,
|
||||
),
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: MessageListView(
|
||||
parentMessage: parent,
|
||||
),
|
||||
),
|
||||
MessageInput(
|
||||
parentMessage: parent,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
/// Third step of the [tutorial](https://getstream.io/chat/flutter/tutorial/)
|
||||
///
|
||||
/// So far you’ve learned how to use the default widgets.
|
||||
/// The library has been designed with composition in mind and to allow all common customizations to be very easy.
|
||||
/// This means that you can change any component in your application by swapping the default widgets with the ones you build yourself.
|
||||
///
|
||||
/// Let’s see how we can make some changes to the SDK’s UI components.
|
||||
/// We start by changing how channel previews are shown in the channel list and include the number of unread messages for each.
|
||||
///
|
||||
/// We're passing a custom widget to [ChannelListView.channelPreviewBuilder], this will override the default [ChannelPreview] and allows you to create one yourself.
|
||||
///
|
||||
/// There are a couple interesting things we do in this widget:
|
||||
///
|
||||
/// - Instead of creating a whole new style for the channel name, we inherit the text style from the parent theme ([StreamChatTheme.of]) and only change the color attribute
|
||||
///
|
||||
/// - We loop over the list of channel messages to search for the first not deleted message ([Channel.state.messages])
|
||||
///
|
||||
/// - We retrieve the count of unread messages from [Channel.state]
|
||||
void main() async {
|
||||
final client = StreamChatClient(
|
||||
's2dxdhpxd94g',
|
||||
logLevel: Level.INFO,
|
||||
);
|
||||
|
||||
await client.setUser(
|
||||
User(id: 'super-band-9'),
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
|
||||
);
|
||||
|
||||
runApp(MyApp(client));
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
final StreamChatClient client;
|
||||
|
||||
MyApp(this.client);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
builder: (context, child) => StreamChat(
|
||||
child: child,
|
||||
client: client,
|
||||
),
|
||||
home: ChannelListPage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelListPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: ChannelsBloc(
|
||||
child: ChannelListView(
|
||||
filter: {
|
||||
'members': {
|
||||
'\$in': [StreamChat.of(context).user.id],
|
||||
}
|
||||
},
|
||||
channelPreviewBuilder: _channelPreviewBuilder,
|
||||
sort: [SortOption('last_message_at')],
|
||||
pagination: PaginationParams(
|
||||
limit: 20,
|
||||
),
|
||||
channelWidget: ChannelPage(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _channelPreviewBuilder(BuildContext context, Channel channel) {
|
||||
final lastMessage = channel.state.messages.reversed
|
||||
.firstWhere((message) => !message.isDeleted);
|
||||
|
||||
final subtitle = (lastMessage == null ? "nothing yet" : lastMessage.text);
|
||||
final opacity = channel.state.unreadCount > .0 ? 1.0 : 0.5;
|
||||
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => StreamChannel(
|
||||
child: ChannelPage(),
|
||||
channel: channel,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
leading: ChannelImage(
|
||||
channel: channel,
|
||||
),
|
||||
title: ChannelName(
|
||||
textStyle:
|
||||
StreamChatTheme.of(context).channelPreviewTheme.title.copyWith(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(opacity),
|
||||
),
|
||||
),
|
||||
subtitle: Text(subtitle),
|
||||
trailing: channel.state.unreadCount > 0
|
||||
? CircleAvatar(
|
||||
radius: 10,
|
||||
child: Text(channel.state.unreadCount.toString()),
|
||||
)
|
||||
: SizedBox(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelPage extends StatelessWidget {
|
||||
const ChannelPage({
|
||||
Key key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: ChannelHeader(),
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: MessageListView(),
|
||||
),
|
||||
MessageInput(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
/// Fifth step of the [tutorial](https://getstream.io/chat/flutter/tutorial/)
|
||||
///
|
||||
/// Customizing how messages are rendered is another very common use-case that the SDK supports easily.
|
||||
///
|
||||
/// Replace the built-in message component with your own is done by passing it as a builder function to the [MessageListView] widget.
|
||||
///
|
||||
/// The message builder function will get the usual [BuildContext] argument as well as the [Message] object and its position inside the list.
|
||||
///
|
||||
/// If you look at the code you can see that we use [StreamChat.of] to retrieve the current user so that we can style messages own messages in a different way.
|
||||
///
|
||||
/// Since custom widgets and builders are always children of [StreamChat] or part of a [Channel],
|
||||
/// you can use [StreamChat.of], [StreamChannel.of] and [StreamChatTheme.of] to use the API client directly
|
||||
/// or to retrieve outer scope needed such as messages from the [Channel.state].
|
||||
void main() async {
|
||||
final client = StreamChatClient(
|
||||
's2dxdhpxd94g',
|
||||
logLevel: Level.INFO,
|
||||
);
|
||||
|
||||
await client.setUser(
|
||||
User(id: 'super-band-9'),
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
|
||||
);
|
||||
|
||||
runApp(MyApp(client));
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
final StreamChatClient client;
|
||||
|
||||
MyApp(this.client);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
builder: (context, child) => StreamChat(
|
||||
child: child,
|
||||
client: client,
|
||||
),
|
||||
home: Container(
|
||||
child: ChannelListPage(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelListPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: ChannelsBloc(
|
||||
child: ChannelListView(
|
||||
filter: {
|
||||
'members': {
|
||||
'\$in': [StreamChat.of(context).user.id],
|
||||
}
|
||||
},
|
||||
sort: [SortOption('last_message_at')],
|
||||
pagination: PaginationParams(
|
||||
limit: 20,
|
||||
),
|
||||
channelWidget: ChannelPage(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelPage extends StatelessWidget {
|
||||
const ChannelPage({
|
||||
Key key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: ChannelHeader(),
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: MessageListView(
|
||||
messageBuilder: _messageBuilder,
|
||||
),
|
||||
),
|
||||
MessageInput(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _messageBuilder(
|
||||
BuildContext context,
|
||||
MessageDetails details,
|
||||
List<Message> messages,
|
||||
) {
|
||||
final message = details.message;
|
||||
final color = details.isMyMessage ? Colors.red : Colors.blue;
|
||||
if (message.isSystem) {
|
||||
return SizedBox();
|
||||
}
|
||||
return MessageWidget(
|
||||
message: message,
|
||||
messageTheme: details.isMyMessage
|
||||
? StreamChatTheme.of(context).ownMessageTheme
|
||||
: StreamChatTheme.of(context).otherMessageTheme,
|
||||
borderSide: BorderSide(
|
||||
color: color,
|
||||
width: 2,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 2,
|
||||
horizontal: 4,
|
||||
),
|
||||
attachmentBorderSide: BorderSide(
|
||||
color: color,
|
||||
width: 2,
|
||||
),
|
||||
attachmentPadding: EdgeInsets.all(8),
|
||||
borderRadiusGeometry: BorderRadius.vertical(
|
||||
top: !details.isLastUser ? Radius.circular(16) : Radius.zero,
|
||||
bottom: !details.isNextUser ? Radius.circular(16) : Radius.zero,
|
||||
),
|
||||
showSendingIndicator: false,
|
||||
reverse: false,
|
||||
showUserAvatar:
|
||||
details.isNextUser ? DisplayWidget.hide : DisplayWidget.show,
|
||||
showTimestamp: !details.isNextUser,
|
||||
showUsername: !details.isNextUser,
|
||||
showReactions: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,331 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import 'main.dart';
|
||||
import 'routes/routes.dart';
|
||||
|
||||
class GroupChatDetailsScreen extends StatefulWidget {
|
||||
final List<User> selectedUsers;
|
||||
|
||||
const GroupChatDetailsScreen({
|
||||
Key key,
|
||||
@required this.selectedUsers,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_GroupChatDetailsScreenState createState() => _GroupChatDetailsScreenState();
|
||||
}
|
||||
|
||||
class _GroupChatDetailsScreenState extends State<GroupChatDetailsScreen> {
|
||||
final _selectedUsers = <User>[];
|
||||
|
||||
TextEditingController _groupNameController;
|
||||
|
||||
bool _isGroupNameEmpty = true;
|
||||
|
||||
int get _totalUsers => _selectedUsers.length;
|
||||
|
||||
void _groupNameListener() {
|
||||
final name = _groupNameController.text;
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isGroupNameEmpty = name.isEmpty;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_selectedUsers.addAll(widget.selectedUsers);
|
||||
_groupNameController = TextEditingController()
|
||||
..addListener(_groupNameListener);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_groupNameController?.removeListener(_groupNameListener);
|
||||
_groupNameController?.clear();
|
||||
_groupNameController?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
Navigator.pop(context, _selectedUsers);
|
||||
return false;
|
||||
},
|
||||
child: Scaffold(
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
appBar: AppBar(
|
||||
brightness: Theme.of(context).brightness,
|
||||
elevation: 1,
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||
leading: const StreamBackButton(),
|
||||
title: Text(
|
||||
'Name of Group Chat',
|
||||
style: TextStyle(
|
||||
color: StreamChatTheme.of(context).colorTheme.black,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
centerTitle: true,
|
||||
bottom: PreferredSize(
|
||||
preferredSize: Size.fromHeight(kToolbarHeight),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
'NAME',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _groupNameController,
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
errorBorder: InputBorder.none,
|
||||
disabledBorder: InputBorder.none,
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
hintText: 'Choose a group chat name',
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 14,
|
||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
StreamNeumorphicButton(
|
||||
child: IconButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
icon: StreamSvgIcon.check(
|
||||
size: 24,
|
||||
color: _isGroupNameEmpty
|
||||
? StreamChatTheme.of(context).colorTheme.grey
|
||||
: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
),
|
||||
onPressed: _isGroupNameEmpty
|
||||
? null
|
||||
: () async {
|
||||
try {
|
||||
final groupName = _groupNameController.text;
|
||||
final client = StreamChat.of(context).client;
|
||||
final channel = client.channel('messaging',
|
||||
id: Uuid().v4(),
|
||||
extraData: {
|
||||
'members': [
|
||||
client.state.user.id,
|
||||
..._selectedUsers.map((e) => e.id),
|
||||
],
|
||||
'name': groupName,
|
||||
});
|
||||
await channel.watch();
|
||||
Navigator.pushNamedAndRemoveUntil(
|
||||
context,
|
||||
Routes.CHANNEL_PAGE,
|
||||
ModalRoute.withName(Routes.HOME),
|
||||
arguments: ChannelPageArgs(channel: channel),
|
||||
);
|
||||
} catch (err) {
|
||||
_showErrorAlert();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: ConnectionStatusBuilder(
|
||||
statusBuilder: (context, status) {
|
||||
String statusString = '';
|
||||
bool showStatus = true;
|
||||
|
||||
switch (status) {
|
||||
case ConnectionStatus.connected:
|
||||
statusString = 'Connected';
|
||||
showStatus = false;
|
||||
break;
|
||||
case ConnectionStatus.connecting:
|
||||
statusString = 'Reconnecting...';
|
||||
break;
|
||||
case ConnectionStatus.disconnected:
|
||||
statusString = 'Disconnected';
|
||||
break;
|
||||
}
|
||||
return InfoTile(
|
||||
showMessage: showStatus,
|
||||
tileAnchor: Alignment.topCenter,
|
||||
childAnchor: Alignment.topCenter,
|
||||
message: statusString,
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: double.maxFinite,
|
||||
decoration: BoxDecoration(
|
||||
gradient:
|
||||
StreamChatTheme.of(context).colorTheme.bgGradient,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 8,
|
||||
horizontal: 8,
|
||||
),
|
||||
child: Text(
|
||||
'$_totalUsers ${_totalUsers > 1 ? 'Members' : 'Member'}',
|
||||
style: TextStyle(
|
||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onPanDown: (_) => FocusScope.of(context).unfocus(),
|
||||
child: ListView.separated(
|
||||
itemCount: _selectedUsers.length + 1,
|
||||
separatorBuilder: (_, __) => Container(
|
||||
height: 1,
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.greyWhisper,
|
||||
),
|
||||
itemBuilder: (_, index) {
|
||||
if (index == _selectedUsers.length) {
|
||||
return Container(
|
||||
height: 1,
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.greyWhisper,
|
||||
);
|
||||
}
|
||||
final user = _selectedUsers[index];
|
||||
return ListTile(
|
||||
key: ObjectKey(user),
|
||||
leading: UserAvatar(
|
||||
user: user,
|
||||
constraints: BoxConstraints.tightFor(
|
||||
width: 40,
|
||||
height: 40,
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
user.name,
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 8,
|
||||
),
|
||||
trailing: IconButton(
|
||||
icon: Icon(
|
||||
Icons.clear_rounded,
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black,
|
||||
),
|
||||
padding: const EdgeInsets.all(0),
|
||||
splashRadius: 24,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedUsers.remove(user);
|
||||
});
|
||||
if (_selectedUsers.isEmpty) {
|
||||
Navigator.pop(context, _selectedUsers);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showErrorAlert() {
|
||||
showModalBottomSheet(
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||
context: context,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(16.0),
|
||||
topRight: Radius.circular(16.0),
|
||||
)),
|
||||
builder: (context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 26.0,
|
||||
),
|
||||
StreamSvgIcon.error(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentRed,
|
||||
size: 24.0,
|
||||
),
|
||||
SizedBox(
|
||||
height: 26.0,
|
||||
),
|
||||
Text(
|
||||
'Something went wrong',
|
||||
style: StreamChatTheme.of(context).textTheme.headlineBold,
|
||||
),
|
||||
SizedBox(
|
||||
height: 7.0,
|
||||
),
|
||||
Text('The operation couldn\'t be completed.'),
|
||||
SizedBox(
|
||||
height: 36.0,
|
||||
),
|
||||
Container(
|
||||
color:
|
||||
StreamChatTheme.of(context).colorTheme.black.withOpacity(.08),
|
||||
height: 1.0,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
FlatButton(
|
||||
child: Text(
|
||||
'OK',
|
||||
style: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.bodyBold
|
||||
.copyWith(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.accentBlue),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,834 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:example/chat_info_screen.dart';
|
||||
import 'package:example/choose_user_page.dart';
|
||||
import 'package:example/group_info_screen.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
import 'package:stream_chat_persistence/stream_chat_persistence.dart';
|
||||
import 'package:streaming_shared_preferences/streaming_shared_preferences.dart';
|
||||
|
||||
import 'notifications_service.dart';
|
||||
import 'routes/app_routes.dart';
|
||||
import 'routes/routes.dart';
|
||||
import 'search_text_field.dart';
|
||||
|
||||
final chatPersistentClient = StreamChatPersistenceClient(
|
||||
logLevel: Level.INFO,
|
||||
connectionMode: ConnectionMode.background,
|
||||
);
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final secureStorage = FlutterSecureStorage();
|
||||
|
||||
final apiKey = await secureStorage.read(key: kStreamApiKey);
|
||||
final userId = await secureStorage.read(key: kStreamUserId);
|
||||
|
||||
final client = StreamChatClient(
|
||||
apiKey ?? kDefaultStreamApiKey,
|
||||
logLevel: Level.INFO,
|
||||
)..chatPersistenceClient = chatPersistentClient;
|
||||
|
||||
if (userId != null) {
|
||||
final token = await secureStorage.read(key: kStreamToken);
|
||||
await client.setUser(
|
||||
User(id: userId),
|
||||
token,
|
||||
);
|
||||
}
|
||||
|
||||
runApp(MyApp(client));
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
final StreamChatClient client;
|
||||
|
||||
MyApp(this.client);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder<StreamingSharedPreferences>(
|
||||
future: StreamingSharedPreferences.instance,
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return SizedBox();
|
||||
}
|
||||
return PreferenceBuilder<int>(
|
||||
preference: snapshot.data.getInt(
|
||||
'theme',
|
||||
defaultValue: 0,
|
||||
),
|
||||
builder: (context, snapshot) => MaterialApp(
|
||||
builder: (context, child) {
|
||||
return StreamChat(
|
||||
client: client,
|
||||
onBackgroundEventReceived: showLocalNotification,
|
||||
child: Builder(
|
||||
builder: (context) => AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
child: child,
|
||||
value: SystemUiOverlayStyle(
|
||||
systemNavigationBarColor:
|
||||
StreamChatTheme.of(context).colorTheme.white,
|
||||
systemNavigationBarIconBrightness:
|
||||
Theme.of(context).brightness == Brightness.dark
|
||||
? Brightness.light
|
||||
: Brightness.dark,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData.light(),
|
||||
darkTheme: ThemeData.dark(),
|
||||
themeMode: {
|
||||
-1: ThemeMode.dark,
|
||||
0: ThemeMode.system,
|
||||
1: ThemeMode.light,
|
||||
}[snapshot],
|
||||
onGenerateRoute: AppRoutes.generateRoute,
|
||||
initialRoute:
|
||||
client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
@override
|
||||
_HomePageState createState() => _HomePageState();
|
||||
}
|
||||
|
||||
class _HomePageState extends State<HomePage> {
|
||||
int _currentIndex = 0;
|
||||
|
||||
bool _isSelected(int index) => _currentIndex == index;
|
||||
|
||||
List<BottomNavigationBarItem> get _navBarItems {
|
||||
return <BottomNavigationBarItem>[
|
||||
BottomNavigationBarItem(
|
||||
icon: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
StreamSvgIcon.message(
|
||||
color: _isSelected(0)
|
||||
? StreamChatTheme.of(context).colorTheme.black
|
||||
: Colors.grey,
|
||||
),
|
||||
Positioned(
|
||||
top: -3,
|
||||
right: -16,
|
||||
child: UnreadIndicator(),
|
||||
),
|
||||
],
|
||||
),
|
||||
label: 'Chats',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
StreamSvgIcon.mentions(
|
||||
color: _isSelected(1)
|
||||
? StreamChatTheme.of(context).colorTheme.black
|
||||
: Colors.grey,
|
||||
),
|
||||
],
|
||||
),
|
||||
label: 'Mentions',
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final user = StreamChat.of(context).user;
|
||||
return Scaffold(
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
appBar: ChannelListHeader(
|
||||
onNewChatButtonTap: () {
|
||||
Navigator.pushNamed(context, Routes.NEW_CHAT);
|
||||
},
|
||||
preNavigationCallback: () {
|
||||
FocusScope.of(context).requestFocus(FocusNode());
|
||||
},
|
||||
),
|
||||
drawer: _buildDrawer(context, user),
|
||||
drawerEdgeDragWidth: 50,
|
||||
bottomNavigationBar: BottomNavigationBar(
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||
currentIndex: _currentIndex,
|
||||
items: _navBarItems,
|
||||
selectedLabelStyle: StreamChatTheme.of(context).textTheme.footnoteBold,
|
||||
unselectedLabelStyle:
|
||||
StreamChatTheme.of(context).textTheme.footnoteBold,
|
||||
type: BottomNavigationBarType.fixed,
|
||||
selectedItemColor: StreamChatTheme.of(context).colorTheme.black,
|
||||
unselectedItemColor: Colors.grey,
|
||||
onTap: (index) {
|
||||
setState(() => _currentIndex = index);
|
||||
},
|
||||
),
|
||||
body: IndexedStack(
|
||||
index: _currentIndex,
|
||||
children: [
|
||||
ChannelListPage(),
|
||||
UserMentionPage(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Drawer _buildDrawer(BuildContext context, User user) {
|
||||
return Drawer(
|
||||
child: Container(
|
||||
color: StreamChatTheme.of(context).colorTheme.white,
|
||||
child: SafeArea(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: MediaQuery.of(context).viewPadding.top + 8,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
bottom: 20.0,
|
||||
left: 8,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
UserAvatar(
|
||||
user: user,
|
||||
showOnlineStatus: false,
|
||||
constraints: BoxConstraints.tight(Size.fromRadius(20)),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16.0),
|
||||
child: Text(
|
||||
user.name,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
leading: StreamSvgIcon.penWrite(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(.5),
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.popAndPushNamed(
|
||||
context,
|
||||
Routes.NEW_CHAT,
|
||||
);
|
||||
},
|
||||
title: Text(
|
||||
'New direct message',
|
||||
style: TextStyle(
|
||||
fontSize: 14.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
leading: StreamSvgIcon.contacts(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(.5),
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.popAndPushNamed(
|
||||
context,
|
||||
Routes.NEW_GROUP_CHAT,
|
||||
);
|
||||
},
|
||||
title: Text(
|
||||
'New group',
|
||||
style: TextStyle(
|
||||
fontSize: 14.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: ListTile(
|
||||
onTap: () async {
|
||||
Navigator.pop(context);
|
||||
|
||||
final secureStorage = FlutterSecureStorage();
|
||||
await secureStorage.deleteAll();
|
||||
|
||||
StreamChat.of(context).client.disconnect(
|
||||
clearUser: true,
|
||||
);
|
||||
|
||||
await Navigator.pushReplacementNamed(
|
||||
context,
|
||||
Routes.CHOOSE_USER,
|
||||
);
|
||||
},
|
||||
leading: StreamSvgIcon.user(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(.5),
|
||||
),
|
||||
title: Text(
|
||||
'Sign out',
|
||||
style: TextStyle(
|
||||
fontSize: 14.5,
|
||||
),
|
||||
),
|
||||
trailing: IconButton(
|
||||
icon: StreamSvgIcon.Icon_moon(
|
||||
size: 24,
|
||||
),
|
||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
||||
onPressed: () async {
|
||||
final sp = await StreamingSharedPreferences.instance;
|
||||
sp.setInt(
|
||||
'theme',
|
||||
Theme.of(context).brightness == Brightness.dark
|
||||
? 1
|
||||
: -1,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class UserMentionPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final user = StreamChat.of(context).user;
|
||||
return MessageSearchBloc(
|
||||
child: MessageSearchListView(
|
||||
filters: {
|
||||
'members': {
|
||||
r'$in': [user.id],
|
||||
},
|
||||
},
|
||||
messageFilters: {
|
||||
'mentioned_users.id': {
|
||||
r'$contains': user.id,
|
||||
},
|
||||
},
|
||||
sortOptions: [
|
||||
SortOption(
|
||||
'created_at',
|
||||
direction: SortOption.ASC,
|
||||
),
|
||||
],
|
||||
paginationParams: PaginationParams(limit: 20),
|
||||
showResultCount: false,
|
||||
emptyBuilder: (_, __) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, viewportConstraints) {
|
||||
return SingleChildScrollView(
|
||||
physics: AlwaysScrollableScrollPhysics(),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: viewportConstraints.maxHeight,
|
||||
),
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: StreamSvgIcon.mentions(
|
||||
size: 96,
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.greyGainsboro,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'No mentions exist yet...',
|
||||
style: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.body
|
||||
.copyWith(
|
||||
color:
|
||||
StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
onItemTap: (messageResponse) async {
|
||||
final client = StreamChat.of(context).client;
|
||||
final message = messageResponse.message;
|
||||
final channel = client.channel(
|
||||
messageResponse.channel.type,
|
||||
id: messageResponse.channel.id,
|
||||
);
|
||||
if (channel.state == null) {
|
||||
await channel.watch();
|
||||
}
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
Routes.CHANNEL_PAGE,
|
||||
arguments: ChannelPageArgs(
|
||||
channel: channel,
|
||||
initialMessage: message,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelListPage extends StatefulWidget {
|
||||
@override
|
||||
_ChannelListPageState createState() => _ChannelListPageState();
|
||||
}
|
||||
|
||||
class _ChannelListPageState extends State<ChannelListPage> {
|
||||
TextEditingController _controller;
|
||||
|
||||
String _channelQuery = '';
|
||||
|
||||
bool _isSearchActive = false;
|
||||
|
||||
Timer _debounce;
|
||||
|
||||
void _channelQueryListener() {
|
||||
if (_debounce?.isActive ?? false) _debounce.cancel();
|
||||
_debounce = Timer(const Duration(milliseconds: 350), () {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_channelQuery = _controller.text;
|
||||
_isSearchActive = _channelQuery.isNotEmpty;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = TextEditingController()..addListener(_channelQueryListener);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller?.removeListener(_channelQueryListener);
|
||||
_controller?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final user = StreamChat.of(context).user;
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
if (_isSearchActive) {
|
||||
_controller.clear();
|
||||
setState(() => _isSearchActive = false);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
child: ChannelsBloc(
|
||||
child: MessageSearchBloc(
|
||||
child: NestedScrollView(
|
||||
floatHeaderSlivers: true,
|
||||
headerSliverBuilder: (_, __) => [
|
||||
SliverToBoxAdapter(
|
||||
child: SearchTextField(
|
||||
controller: _controller,
|
||||
showCloseButton: _isSearchActive,
|
||||
),
|
||||
),
|
||||
],
|
||||
body: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 350),
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onPanDown: (_) => FocusScope.of(context).unfocus(),
|
||||
child: _isSearchActive
|
||||
? MessageSearchListView(
|
||||
messageQuery: _channelQuery,
|
||||
filters: {
|
||||
'members': {
|
||||
r'$in': [user.id]
|
||||
}
|
||||
},
|
||||
sortOptions: [
|
||||
SortOption(
|
||||
'created_at',
|
||||
direction: SortOption.ASC,
|
||||
),
|
||||
],
|
||||
pullToRefresh: false,
|
||||
paginationParams: PaginationParams(limit: 20),
|
||||
emptyBuilder: (_, query) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, viewportConstraints) {
|
||||
return SingleChildScrollView(
|
||||
physics: AlwaysScrollableScrollPhysics(),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: viewportConstraints.maxHeight,
|
||||
),
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: StreamSvgIcon.search(
|
||||
size: 96,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'No results for \"$query\"...',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
onItemTap: (messageResponse) async {
|
||||
FocusScope.of(context).requestFocus(FocusNode());
|
||||
final client = StreamChat.of(context).client;
|
||||
final message = messageResponse.message;
|
||||
final channel = client.channel(
|
||||
messageResponse.channel.type,
|
||||
id: messageResponse.channel.id,
|
||||
);
|
||||
if (channel.state == null) {
|
||||
await channel.watch();
|
||||
}
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
Routes.CHANNEL_PAGE,
|
||||
arguments: ChannelPageArgs(
|
||||
channel: channel,
|
||||
initialMessage: message,
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
: ChannelListView(
|
||||
onStartChatPressed: () {
|
||||
Navigator.pushNamed(context, Routes.NEW_CHAT);
|
||||
},
|
||||
swipeToAction: true,
|
||||
filter: {
|
||||
'members': {
|
||||
r'$in': [user.id],
|
||||
},
|
||||
},
|
||||
options: {
|
||||
'presence': true,
|
||||
},
|
||||
pagination: PaginationParams(
|
||||
limit: 20,
|
||||
),
|
||||
channelWidget: ChannelPage(),
|
||||
onViewInfoTap: (channel) {
|
||||
if (channel.memberCount == 2 && channel.isDistinct) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => StreamChannel(
|
||||
channel: channel,
|
||||
child: ChatInfoScreen(
|
||||
user: channel.state.members.first.user,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => StreamChannel(
|
||||
channel: channel,
|
||||
child: GroupInfoScreen(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelPageArgs {
|
||||
final Channel channel;
|
||||
final Message initialMessage;
|
||||
|
||||
const ChannelPageArgs({
|
||||
this.channel,
|
||||
this.initialMessage,
|
||||
});
|
||||
}
|
||||
|
||||
class ChannelPage extends StatefulWidget {
|
||||
final int initialScrollIndex;
|
||||
final double initialAlignment;
|
||||
final bool highlightInitialMessage;
|
||||
|
||||
const ChannelPage({
|
||||
Key key,
|
||||
this.initialScrollIndex,
|
||||
this.initialAlignment,
|
||||
this.highlightInitialMessage = false,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_ChannelPageState createState() => _ChannelPageState();
|
||||
}
|
||||
|
||||
class _ChannelPageState extends State<ChannelPage> {
|
||||
Message _quotedMessage;
|
||||
FocusNode _focusNode;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_focusNode = FocusNode();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _reply(Message message) {
|
||||
setState(() => _quotedMessage = message);
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
_focusNode.requestFocus();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
appBar: ChannelHeader(
|
||||
showTypingIndicator: false,
|
||||
onImageTap: () async {
|
||||
var channel = StreamChannel.of(context).channel;
|
||||
|
||||
if (channel.memberCount == 2 && channel.isDistinct) {
|
||||
final currentUser = StreamChat.of(context).user;
|
||||
final otherUser = channel.state.members.firstWhere(
|
||||
(element) => element.user.id != currentUser.id,
|
||||
orElse: () => null,
|
||||
);
|
||||
if (otherUser != null) {
|
||||
final pop = await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => StreamChannel(
|
||||
child: ChatInfoScreen(
|
||||
user: otherUser.user,
|
||||
),
|
||||
channel: channel,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (pop == true) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => StreamChannel(
|
||||
child: GroupInfoScreen(),
|
||||
channel: channel,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
MessageListView(
|
||||
initialScrollIndex: widget.initialScrollIndex,
|
||||
initialAlignment: widget.initialAlignment,
|
||||
highlightInitialMessage: widget.highlightInitialMessage,
|
||||
onMessageSwiped: _reply,
|
||||
onReplyTap: _reply,
|
||||
threadBuilder: (_, parentMessage) {
|
||||
return ThreadPage(
|
||||
parent: parentMessage,
|
||||
);
|
||||
},
|
||||
onShowMessage: (m, c) async {
|
||||
final client = StreamChat.of(context).client;
|
||||
final message = m;
|
||||
final channel = client.channel(
|
||||
c.type,
|
||||
id: c.id,
|
||||
);
|
||||
if (channel.state == null) {
|
||||
await channel.watch();
|
||||
}
|
||||
Navigator.pushReplacementNamed(
|
||||
context,
|
||||
Routes.CHANNEL_PAGE,
|
||||
arguments: ChannelPageArgs(
|
||||
channel: channel,
|
||||
initialMessage: message,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.whiteSnow
|
||||
.withOpacity(.9),
|
||||
child: TypingIndicator(
|
||||
alignment: Alignment.centerLeft,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 4,
|
||||
),
|
||||
style: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.footnote
|
||||
.copyWith(
|
||||
color:
|
||||
StreamChatTheme.of(context).colorTheme.grey),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
MessageInput(
|
||||
focusNode: _focusNode,
|
||||
quotedMessage: _quotedMessage,
|
||||
onQuotedMessageCleared: () {
|
||||
setState(() => _quotedMessage = null);
|
||||
_focusNode.unfocus();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ThreadPage extends StatefulWidget {
|
||||
final Message parent;
|
||||
final int initialScrollIndex;
|
||||
final double initialAlignment;
|
||||
|
||||
ThreadPage({
|
||||
Key key,
|
||||
this.parent,
|
||||
this.initialScrollIndex,
|
||||
this.initialAlignment,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_ThreadPageState createState() => _ThreadPageState();
|
||||
}
|
||||
|
||||
class _ThreadPageState extends State<ThreadPage> {
|
||||
Message _quotedMessage;
|
||||
FocusNode _focusNode = FocusNode();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _reply(Message message) {
|
||||
setState(() => _quotedMessage = message);
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
_focusNode.requestFocus();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
appBar: ThreadHeader(
|
||||
parent: widget.parent,
|
||||
),
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: MessageListView(
|
||||
parentMessage: widget.parent,
|
||||
initialScrollIndex: widget.initialScrollIndex,
|
||||
initialAlignment: widget.initialAlignment,
|
||||
onMessageSwiped: _reply,
|
||||
onReplyTap: _reply,
|
||||
),
|
||||
),
|
||||
if (widget.parent.type != 'deleted')
|
||||
MessageInput(
|
||||
parentMessage: widget.parent,
|
||||
focusNode: _focusNode,
|
||||
quotedMessage: _quotedMessage,
|
||||
onQuotedMessageCleared: () {
|
||||
setState(() => _quotedMessage = null);
|
||||
_focusNode.unfocus();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
/// Second step of the [tutorial](https://getstream.io/chat/flutter/tutorial/)
|
||||
///
|
||||
/// Most chat applications handle more than just one single conversation.
|
||||
/// Apps like Facebook Messenger, Whatsapp and Telegram allows you to have multiple one to one and group conversations.
|
||||
///
|
||||
/// Let’s find out how we can change our application chat screen to display the list of conversations and navigate between them.
|
||||
///
|
||||
/// > Note: the SDK uses Flutter’s [Navigator] to move from one route to another, this allows us to avoid any boiler-plate code.
|
||||
/// > Of course you can take total control of how navigation works by customizing widgets like [Channel] and [ChannelList].
|
||||
///
|
||||
/// If you run the application, you will see that the first screen shows a list of conversations, you can open each by tapping and go back to the list.
|
||||
///
|
||||
/// Every single widget involved in this UI can be customized or swapped with your own.
|
||||
///
|
||||
/// The [ChannelListPage] widget retrieves the list of channels based on a custom query and ordering.
|
||||
/// In this case we are showing the list of channels the current user is a member and we order them based on the time they had a new message.
|
||||
/// [ChannelListView] handles pagination and updates automatically out of the box when new channels are created or when a new message is added to a channel.
|
||||
void main() async {
|
||||
final client = StreamChatClient(
|
||||
's2dxdhpxd94g',
|
||||
logLevel: Level.INFO,
|
||||
);
|
||||
|
||||
await client.setUser(
|
||||
User(id: 'super-band-9'),
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
|
||||
);
|
||||
|
||||
runApp(MyApp(client));
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
final StreamChatClient client;
|
||||
|
||||
MyApp(this.client);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
builder: (context, child) => StreamChat(
|
||||
client: client,
|
||||
child: child,
|
||||
),
|
||||
home: ChannelListPage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelListPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: ChannelsBloc(
|
||||
child: ChannelListView(
|
||||
filter: {
|
||||
// 'members': {
|
||||
// '\$in': [StreamChat.of(context).user.id],
|
||||
// }
|
||||
},
|
||||
sort: [SortOption('last_message_at')],
|
||||
pagination: PaginationParams(
|
||||
limit: 20,
|
||||
),
|
||||
channelWidget: ChannelPage(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelPage extends StatelessWidget {
|
||||
const ChannelPage({
|
||||
Key key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: ChannelHeader(),
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: MessageListView(),
|
||||
),
|
||||
MessageInput(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,417 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
import 'chips_input_text_field.dart';
|
||||
import 'main.dart';
|
||||
import 'routes/routes.dart';
|
||||
|
||||
class NewChatScreen extends StatefulWidget {
|
||||
@override
|
||||
_NewChatScreenState createState() => _NewChatScreenState();
|
||||
}
|
||||
|
||||
class _NewChatScreenState extends State<NewChatScreen> {
|
||||
final _chipInputTextFieldStateKey =
|
||||
GlobalKey<ChipInputTextFieldState<User>>();
|
||||
|
||||
TextEditingController _controller;
|
||||
|
||||
ChipInputTextFieldState get _chipInputTextFieldState =>
|
||||
_chipInputTextFieldStateKey.currentState;
|
||||
|
||||
String _userNameQuery = '';
|
||||
|
||||
final _selectedUsers = <User>{};
|
||||
|
||||
final _searchFocusNode = FocusNode();
|
||||
final _messageInputFocusNode = FocusNode();
|
||||
|
||||
bool _isSearchActive = false;
|
||||
|
||||
Channel channel;
|
||||
|
||||
Timer _debounce;
|
||||
|
||||
bool _showUserList = true;
|
||||
|
||||
void _userNameListener() {
|
||||
if (_debounce?.isActive ?? false) _debounce.cancel();
|
||||
_debounce = Timer(const Duration(milliseconds: 350), () {
|
||||
if (mounted)
|
||||
setState(() {
|
||||
_userNameQuery = _controller.text;
|
||||
_isSearchActive = _userNameQuery.isNotEmpty;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
channel = StreamChat.of(context).client.channel('messaging');
|
||||
_controller = TextEditingController()..addListener(_userNameListener);
|
||||
|
||||
_searchFocusNode.addListener(() async {
|
||||
if (_searchFocusNode.hasFocus && !_showUserList) {
|
||||
setState(() {
|
||||
_showUserList = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
_messageInputFocusNode.addListener(() async {
|
||||
if (_messageInputFocusNode.hasFocus && _selectedUsers.isNotEmpty) {
|
||||
final chatState = StreamChat.of(context);
|
||||
|
||||
final res = await chatState.client.queryChannels(
|
||||
options: {
|
||||
'state': false,
|
||||
'watch': false,
|
||||
},
|
||||
filter: {
|
||||
'members': [
|
||||
..._selectedUsers.map((e) => e.id),
|
||||
chatState.user.id,
|
||||
],
|
||||
'distinct': true,
|
||||
},
|
||||
messageLimit: 0,
|
||||
paginationParams: PaginationParams(
|
||||
limit: 1,
|
||||
),
|
||||
);
|
||||
|
||||
final _channelExisted = res.length == 1;
|
||||
if (_channelExisted) {
|
||||
channel = res.first;
|
||||
await channel.watch();
|
||||
} else {
|
||||
channel = chatState.client.channel(
|
||||
'messaging',
|
||||
extraData: {
|
||||
'members': [
|
||||
..._selectedUsers.map((e) => e.id),
|
||||
chatState.user.id,
|
||||
],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_showUserList = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_searchFocusNode.dispose();
|
||||
_messageInputFocusNode.dispose();
|
||||
_controller?.clear();
|
||||
_controller?.removeListener(_userNameListener);
|
||||
_controller?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
appBar: AppBar(
|
||||
brightness: Theme.of(context).brightness,
|
||||
elevation: 0,
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||
leading: const StreamBackButton(),
|
||||
title: Text(
|
||||
'New Chat',
|
||||
style: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.headlineBold
|
||||
.copyWith(color: StreamChatTheme.of(context).colorTheme.black),
|
||||
),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: ConnectionStatusBuilder(
|
||||
statusBuilder: (context, status) {
|
||||
String statusString = '';
|
||||
bool showStatus = true;
|
||||
|
||||
switch (status) {
|
||||
case ConnectionStatus.connected:
|
||||
statusString = 'Connected';
|
||||
showStatus = false;
|
||||
break;
|
||||
case ConnectionStatus.connecting:
|
||||
statusString = 'Reconnecting...';
|
||||
break;
|
||||
case ConnectionStatus.disconnected:
|
||||
statusString = 'Disconnected';
|
||||
break;
|
||||
}
|
||||
return InfoTile(
|
||||
showMessage: showStatus,
|
||||
tileAnchor: Alignment.topCenter,
|
||||
childAnchor: Alignment.topCenter,
|
||||
message: statusString,
|
||||
child: StreamChannel(
|
||||
showLoading: false,
|
||||
channel: channel,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ChipsInputTextField<User>(
|
||||
key: _chipInputTextFieldStateKey,
|
||||
controller: _controller,
|
||||
focusNode: _searchFocusNode,
|
||||
chipBuilder: (context, user) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
_chipInputTextFieldState.removeItem(user);
|
||||
_searchFocusNode.requestFocus();
|
||||
},
|
||||
child: Stack(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.greyGainsboro,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
padding: const EdgeInsets.only(left: 24),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8, 4, 12, 4),
|
||||
child: Text(
|
||||
user.name,
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
foregroundDecoration: BoxDecoration(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.overlay,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: UserAvatar(
|
||||
showOnlineStatus: false,
|
||||
user: user,
|
||||
constraints: BoxConstraints.tightFor(
|
||||
height: 24,
|
||||
width: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
StreamSvgIcon.close(),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
onChipAdded: (user) {
|
||||
setState(() => _selectedUsers.add(user));
|
||||
},
|
||||
onChipRemoved: (user) {
|
||||
setState(() => _selectedUsers.remove(user));
|
||||
},
|
||||
),
|
||||
if (!_isSearchActive && !_selectedUsers.isNotEmpty)
|
||||
Container(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
Routes.NEW_GROUP_CHAT,
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
StreamNeumorphicButton(
|
||||
child: Center(
|
||||
child: StreamSvgIcon.contacts(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.accentBlue,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
'Create a Group',
|
||||
style: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.bodyBold,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (_showUserList)
|
||||
Container(
|
||||
width: double.maxFinite,
|
||||
decoration: BoxDecoration(
|
||||
gradient:
|
||||
StreamChatTheme.of(context).colorTheme.bgGradient,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 8,
|
||||
horizontal: 8,
|
||||
),
|
||||
child: Text(
|
||||
_isSearchActive
|
||||
? "Matches for \"$_userNameQuery\""
|
||||
: 'On the platform',
|
||||
style: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.footnote
|
||||
.copyWith(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(.5))),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: _showUserList
|
||||
? GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onPanDown: (_) => FocusScope.of(context).unfocus(),
|
||||
child: UsersBloc(
|
||||
child: UserListView(
|
||||
selectedUsers: _selectedUsers,
|
||||
groupAlphabetically:
|
||||
_isSearchActive ? false : true,
|
||||
onUserTap: (user, _) {
|
||||
_controller.clear();
|
||||
if (!_selectedUsers.contains(user)) {
|
||||
_chipInputTextFieldState
|
||||
..addItem(user)
|
||||
..pauseItemAddition();
|
||||
} else {
|
||||
_chipInputTextFieldState.removeItem(user);
|
||||
}
|
||||
},
|
||||
pagination: PaginationParams(
|
||||
limit: 25,
|
||||
),
|
||||
filter: {
|
||||
if (_userNameQuery.isNotEmpty)
|
||||
'name': {
|
||||
r'$autocomplete': _userNameQuery,
|
||||
},
|
||||
'id': {
|
||||
r'$ne': StreamChat.of(context).user.id,
|
||||
},
|
||||
},
|
||||
sort: [
|
||||
SortOption(
|
||||
'name',
|
||||
direction: 1,
|
||||
),
|
||||
],
|
||||
emptyBuilder: (_) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, viewportConstraints) {
|
||||
return SingleChildScrollView(
|
||||
physics:
|
||||
AlwaysScrollableScrollPhysics(),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight:
|
||||
viewportConstraints.maxHeight,
|
||||
),
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.all(24),
|
||||
child: StreamSvgIcon.search(
|
||||
size: 96,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'No user matches these keywords...',
|
||||
style: StreamChatTheme.of(
|
||||
context)
|
||||
.textTheme
|
||||
.footnote
|
||||
.copyWith(
|
||||
color: StreamChatTheme
|
||||
.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(.5)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
: FutureBuilder<bool>(
|
||||
future: channel.initialized,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == true) {
|
||||
return MessageListView();
|
||||
}
|
||||
|
||||
return Center(
|
||||
child: Text(
|
||||
'No chats here yet...',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(.5),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
MessageInput(
|
||||
focusNode: _messageInputFocusNode,
|
||||
preMessageSending: (message) async {
|
||||
await channel.watch();
|
||||
return message;
|
||||
},
|
||||
onMessageSent: (m) {
|
||||
Navigator.pushNamedAndRemoveUntil(
|
||||
context,
|
||||
Routes.CHANNEL_PAGE,
|
||||
ModalRoute.withName(Routes.HOME),
|
||||
arguments: ChannelPageArgs(channel: channel),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,339 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
import 'routes/routes.dart';
|
||||
import 'search_text_field.dart';
|
||||
|
||||
class NewGroupChatScreen extends StatefulWidget {
|
||||
@override
|
||||
_NewGroupChatScreenState createState() => _NewGroupChatScreenState();
|
||||
}
|
||||
|
||||
class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
||||
TextEditingController _controller;
|
||||
|
||||
String _userNameQuery = '';
|
||||
|
||||
final _selectedUsers = <User>{};
|
||||
|
||||
bool _isSearchActive = false;
|
||||
|
||||
Timer _debounce;
|
||||
|
||||
void _userNameListener() {
|
||||
if (_debounce?.isActive ?? false) _debounce.cancel();
|
||||
_debounce = Timer(const Duration(milliseconds: 350), () {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_userNameQuery = _controller.text;
|
||||
_isSearchActive = _userNameQuery.isNotEmpty;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = TextEditingController()..addListener(_userNameListener);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller?.clear();
|
||||
_controller?.removeListener(_userNameListener);
|
||||
_controller?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||
appBar: AppBar(
|
||||
elevation: 1,
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||
leading: const StreamBackButton(),
|
||||
title: Text(
|
||||
'Add Group Members',
|
||||
style: TextStyle(
|
||||
color: StreamChatTheme.of(context).colorTheme.black,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
centerTitle: true,
|
||||
actions: [
|
||||
if (_selectedUsers.isNotEmpty)
|
||||
IconButton(
|
||||
icon: StreamSvgIcon.arrow_right(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
),
|
||||
onPressed: () async {
|
||||
final updatedList = await Navigator.pushNamed(
|
||||
context,
|
||||
Routes.NEW_GROUP_CHAT_DETAILS,
|
||||
arguments: _selectedUsers.toList(growable: false),
|
||||
);
|
||||
if (updatedList != null) {
|
||||
setState(() {
|
||||
_selectedUsers
|
||||
..clear()
|
||||
..addAll(updatedList);
|
||||
});
|
||||
}
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
body: ConnectionStatusBuilder(
|
||||
statusBuilder: (context, status) {
|
||||
String statusString = '';
|
||||
bool showStatus = true;
|
||||
|
||||
switch (status) {
|
||||
case ConnectionStatus.connected:
|
||||
statusString = 'Connected';
|
||||
showStatus = false;
|
||||
break;
|
||||
case ConnectionStatus.connecting:
|
||||
statusString = 'Reconnecting...';
|
||||
break;
|
||||
case ConnectionStatus.disconnected:
|
||||
statusString = 'Disconnected';
|
||||
break;
|
||||
}
|
||||
return InfoTile(
|
||||
showMessage: showStatus,
|
||||
tileAnchor: Alignment.topCenter,
|
||||
childAnchor: Alignment.topCenter,
|
||||
message: statusString,
|
||||
child: NestedScrollView(
|
||||
floatHeaderSlivers: true,
|
||||
headerSliverBuilder:
|
||||
(BuildContext context, bool innerBoxIsScrolled) {
|
||||
return <Widget>[
|
||||
SliverToBoxAdapter(
|
||||
child: SearchTextField(
|
||||
controller: _controller,
|
||||
),
|
||||
),
|
||||
if (_selectedUsers.isNotEmpty)
|
||||
SliverToBoxAdapter(
|
||||
child: Container(
|
||||
height: 104,
|
||||
child: ListView.separated(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: _selectedUsers.length,
|
||||
padding: const EdgeInsets.all(8),
|
||||
separatorBuilder: (_, __) => SizedBox(width: 16),
|
||||
itemBuilder: (_, index) {
|
||||
final user = _selectedUsers.elementAt(index);
|
||||
return Column(
|
||||
children: [
|
||||
Stack(
|
||||
children: [
|
||||
UserAvatar(
|
||||
onlineIndicatorAlignment:
|
||||
Alignment(0.9, 0.9),
|
||||
user: user,
|
||||
showOnlineStatus: true,
|
||||
borderRadius: BorderRadius.circular(32),
|
||||
constraints: BoxConstraints.tightFor(
|
||||
height: 64,
|
||||
width: 64,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: -4,
|
||||
right: -4,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
if (_selectedUsers.contains(user)) {
|
||||
setState(() =>
|
||||
_selectedUsers.remove(user));
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.white,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.whiteSnow,
|
||||
),
|
||||
),
|
||||
child: StreamSvgIcon.close(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
user.name.split(' ')[0],
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
SliverPersistentHeader(
|
||||
pinned: true,
|
||||
delegate: _HeaderDelegate(
|
||||
height: 30,
|
||||
child: Container(
|
||||
width: double.maxFinite,
|
||||
decoration: BoxDecoration(
|
||||
gradient:
|
||||
StreamChatTheme.of(context).colorTheme.bgGradient,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 8,
|
||||
horizontal: 8,
|
||||
),
|
||||
child: Text(
|
||||
_isSearchActive
|
||||
? 'Matches for \"$_userNameQuery\"'
|
||||
: 'On the platform',
|
||||
style: TextStyle(
|
||||
color:
|
||||
StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
body: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onPanDown: (_) => FocusScope.of(context).unfocus(),
|
||||
child: UsersBloc(
|
||||
child: UserListView(
|
||||
selectedUsers: _selectedUsers,
|
||||
pullToRefresh: false,
|
||||
groupAlphabetically: _isSearchActive ? false : true,
|
||||
onUserTap: (user, _) {
|
||||
if (!_selectedUsers.contains(user)) {
|
||||
setState(() {
|
||||
_selectedUsers.add(user);
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_selectedUsers.remove(user);
|
||||
});
|
||||
}
|
||||
},
|
||||
pagination: PaginationParams(
|
||||
limit: 25,
|
||||
),
|
||||
filter: {
|
||||
if (_userNameQuery.isNotEmpty)
|
||||
'name': {
|
||||
r'$autocomplete': _userNameQuery,
|
||||
},
|
||||
'id': {
|
||||
r'$ne': StreamChat.of(context).user.id,
|
||||
}
|
||||
},
|
||||
sort: [
|
||||
SortOption(
|
||||
'name',
|
||||
direction: 1,
|
||||
),
|
||||
],
|
||||
emptyBuilder: (_) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, viewportConstraints) {
|
||||
return SingleChildScrollView(
|
||||
physics: AlwaysScrollableScrollPhysics(),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: viewportConstraints.maxHeight,
|
||||
),
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: StreamSvgIcon.search(
|
||||
size: 96,
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.grey,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'No user matches these keywords...',
|
||||
style: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.footnote
|
||||
.copyWith(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _HeaderDelegate extends SliverPersistentHeaderDelegate {
|
||||
final Widget child;
|
||||
final double height;
|
||||
|
||||
const _HeaderDelegate({
|
||||
@required this.child,
|
||||
@required this.height,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(
|
||||
BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||
return Container(
|
||||
color: StreamChatTheme.of(context).colorTheme.white,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
double get maxExtent => height;
|
||||
|
||||
@override
|
||||
double get minExtent => height;
|
||||
|
||||
@override
|
||||
bool shouldRebuild(_HeaderDelegate oldDelegate) => true;
|
||||
}
|
||||