Merge branch 'master' into feature/new-ui

This commit is contained in:
Salvatore Giordano
2020-10-05 10:42:01 +02:00
23 changed files with 886 additions and 567 deletions
+21 -26
View File
@@ -6,9 +6,6 @@ on:
- master - master
- feature/new-ui - feature/new-ui
env:
flutter_version: "1.20.2"
jobs: jobs:
build_and_deploy_ios: build_and_deploy_ios:
runs-on: [macos-latest] runs-on: [macos-latest]
@@ -28,7 +25,7 @@ jobs:
bundle install bundle install
- uses: subosito/[email protected] - uses: subosito/[email protected]
with: with:
flutter-version: ${{ env.flutter_version }} channel: 'stable'
- name: Install firebase-tools - name: Install firebase-tools
run: npm install -g firebase-tools run: npm install -g firebase-tools
- name: Flutter setup - name: Flutter setup
@@ -47,25 +44,23 @@ jobs:
build_and_deploy_android: build_and_deploy_android:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/checkout@v1 - name: Flutter action
- uses: actions/setup-java@v1 uses: subosito/[email protected]
with: with:
java-version: '12.x' channel: 'stable'
- uses: subosito/[email protected] - name: Get dependencies
with: run: flutter pub get
flutter-version: ${{ env.flutter_version }} - name: Coverage fix
- run: | run: |
cd example file=test/coverage_helper_test.dart
flutter pub get echo "// Helper file to make coverage work for all dart files\n" > $file
- name: Build echo "// ignore_for_file: unused_import" >> $file
run: | find lib -name '*.dart' | grep -e '[^g]\.dart' | grep -v '_html.dart' | cut -c4- | awk -v package=stream_chat_flutter '{printf "import '\''package:%s%s'\'';\n", package, $1}' >> $file
cd example echo "" >> $file
flutter build apk echo "void main(){}" >> $file
- name: Deploy cat $file
uses: wzieba/[email protected] - name: Run tests
with: run: flutter test --coverage
appId: ${{secrets.FIREBASE_ANDROID_APPID}} - name: Codecov
token: ${{secrets.FIREBASE_TOKEN}} run: bash <(curl -s https://codecov.io/bash) -c -t ${{ secrets.CODECOV_TOKEN }} -f coverage/lcov.info -F flutter_tool
groups: stream-testers
file: example/build/app/outputs/apk/release/app-release.apk
+42
View File
@@ -1,3 +1,45 @@
## 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 ## 0.2.4
- Update llc dependency - Update llc dependency
+2
View File
@@ -10,6 +10,8 @@
[![Pub](https://img.shields.io/pub/v/stream_chat_flutter.svg)](https://pub.dartlang.org/packages/stream_chat_flutter) [![Pub](https://img.shields.io/pub/v/stream_chat_flutter.svg)](https://pub.dartlang.org/packages/stream_chat_flutter)
![](https://img.shields.io/badge/platform-flutter%20%7C%20flutter%20web-ff69b4.svg?style=flat-square) ![](https://img.shields.io/badge/platform-flutter%20%7C%20flutter%20web-ff69b4.svg?style=flat-square)
[![Gitter](https://badges.gitter.im/GetStream/stream-chat-flutter.svg)](https://gitter.im/GetStream/stream-chat-flutter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Gitter](https://badges.gitter.im/GetStream/stream-chat-flutter.svg)](https://gitter.im/GetStream/stream-chat-flutter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
![CI](https://github.com/GetStream/stream-chat-flutter/workflows/CI/badge.svg?branch=master)
[![codecov](https://codecov.io/gh/GetStream/stream-chat-flutter/branch/master/graph/badge.svg)](https://codecov.io/gh/GetStream/stream-chat-flutter)
<img align="right" src="https://getstream.imgix.net/images/ios-chat-tutorial/iphone_chat_art@1x.png?auto=format,enhance" width="50%" /> <img align="right" src="https://getstream.imgix.net/images/ios-chat-tutorial/iphone_chat_art@1x.png?auto=format,enhance" width="50%" />
+1
View File
@@ -0,0 +1 @@
13ecb9b157bb3e3d1ca2efb15c813a88
@@ -7,7 +7,7 @@
// //
import UserNotifications import UserNotifications
import StreamChatClient //import StreamChatClient
final class NotificationService: UNNotificationServiceExtension { final class NotificationService: UNNotificationServiceExtension {
@@ -26,29 +26,29 @@ final class NotificationService: UNNotificationServiceExtension {
return return
} }
Client.config = .init(apiKey: apiKey, logOptions: .error) // Client.config = .init(apiKey: apiKey, logOptions: .error)
Client.shared.set(user: User(id: userId), token: token) { res in // Client.shared.set(user: User(id: userId), token: token) { res in
guard res.isConnected else { // guard res.isConnected else {
return // return
} // }
//
Client.shared.message(withId: messageId) { [weak self] res in // Client.shared.message(withId: messageId) { [weak self] res in
if let message = res.value?.message, // if let message = res.value?.message,
let channel = res.value?.channel { // let channel = res.value?.channel {
let messageWrapper = MessageWrapper(channel: channel, message: message) // let messageWrapper = MessageWrapper(channel: channel, message: message)
if let encodedData = try? JSONEncoder.stream.encode(messageWrapper), // if let encodedData = try? JSONEncoder.stream.encode(messageWrapper),
let encodedString = String(data: encodedData, encoding: .utf8) { // let encodedString = String(data: encodedData, encoding: .utf8) {
let storedMessages = sharedDefaults.stringArray(forKey: "messageQueue") ?? [] // let storedMessages = sharedDefaults.stringArray(forKey: "messageQueue") ?? []
sharedDefaults.setValue(storedMessages + [encodedString], forKey: "messageQueue") // sharedDefaults.setValue(storedMessages + [encodedString], forKey: "messageQueue")
//
// Modify the notification content here... // // Modify the notification content here...
self?.bestAttemptContent?.title = "[modified] \(self?.bestAttemptContent?.title ?? "<NoContent>")" // self?.bestAttemptContent?.title = "[modified] \(self?.bestAttemptContent?.title ?? "<NoContent>")"
contentHandler(self?.bestAttemptContent ?? request.content) // contentHandler(self?.bestAttemptContent ?? request.content)
} // }
Client.shared.disconnect() // Client.shared.disconnect()
} // }
} // }
} // }
} }
override func serviceExtensionTimeWillExpire() { override func serviceExtensionTimeWillExpire() {
@@ -58,125 +58,125 @@ final class NotificationService: UNNotificationServiceExtension {
} }
} }
public struct MessageWrapper: Encodable { //public struct MessageWrapper: Encodable {
private enum CodingKeys: String, CodingKey { // private enum CodingKeys: String, CodingKey {
case id // case id
case channel // case channel
case type // case type
case user // case user
case created = "created_at" // case created = "created_at"
case updated = "updated_at" // case updated = "updated_at"
case text // case text
case command // case command
case args // case args
case attachments // case attachments
case parentId = "parent_id" // case parentId = "parent_id"
case showReplyInChannel = "show_in_channel" // case showReplyInChannel = "show_in_channel"
case mentionedUsers = "mentioned_users" // case mentionedUsers = "mentioned_users"
} // }
//
init(channel: Channel, message: Message) { // init(channel: Channel, message: Message) {
id = message.id // id = message.id
type = message.type // type = message.type
user = message.user // user = message.user
created = message.created // created = message.created
updated = message.updated // updated = message.updated
text = message.text // text = message.text
command = message.command // command = message.command
args = message.args // args = message.args
attachments = message.attachments // attachments = message.attachments
parentId = message.parentId // parentId = message.parentId
showReplyInChannel = message.showReplyInChannel // showReplyInChannel = message.showReplyInChannel
mentionedUsers = message.mentionedUsers // mentionedUsers = message.mentionedUsers
extraData = message.extraData // extraData = message.extraData
self.channel = ChannelWrapper(channel: channel) // self.channel = ChannelWrapper(channel: channel)
} // }
//
/// A message id. // /// A message id.
public let id: String // public let id: String
/// The channel cid. // /// The channel cid.
public let channel: ChannelWrapper? // public let channel: ChannelWrapper?
/// A message type (see `MessageType`). // /// A message type (see `MessageType`).
public let type: MessageType // public let type: MessageType
/// A user (see `User`). // /// A user (see `User`).
public let user: User // public let user: User
/// A created date. // /// A created date.
public let created: Date // public let created: Date
/// A updated date. // /// A updated date.
public let updated: Date // public let updated: Date
/// A text. // /// A text.
public let text: String // public let text: String
/// A used command name. // /// A used command name.
public let command: String? // public let command: String?
/// A used command args. // /// A used command args.
public let args: String? // public let args: String?
/// Attachments (see `Attachment`). // /// Attachments (see `Attachment`).
public let attachments: [Attachment] // public let attachments: [Attachment]
/// A parent message id. // /// A parent message id.
public let parentId: String? // public let parentId: String?
/// Check if this reply message needs to show in the channel. // /// Check if this reply message needs to show in the channel.
public let showReplyInChannel: Bool // public let showReplyInChannel: Bool
/// Mentioned users (see `User`). // /// Mentioned users (see `User`).
public let mentionedUsers: [User] // public let mentionedUsers: [User]
/// An extra data for the message. // /// An extra data for the message.
public let extraData: Codable? // public let extraData: Codable?
} //}
//
public struct ChannelWrapper: Encodable { //public struct ChannelWrapper: Encodable {
/// Coding keys for the encoding. // /// Coding keys for the encoding.
private enum CodingKeys: String, CodingKey { // private enum CodingKeys: String, CodingKey {
case id // case id
case cid // case cid
case type // case type
case name // case name
case imageURL = "image" // case imageURL = "image"
case members // case members
case lastMessageDate = "last_message_at" // case lastMessageDate = "last_message_at"
case createdBy = "created_by" // case createdBy = "created_by"
case created = "created_at" // case created = "created_at"
case deleted = "deleted_at" // case deleted = "deleted_at"
case frozen // case frozen
} // }
//
init(channel: Channel) { // init(channel: Channel) {
id = channel.id // id = channel.id
cid = channel.cid // cid = channel.cid
type = channel.type // type = channel.type
name = channel.name // name = channel.name
imageURL = channel.imageURL // imageURL = channel.imageURL
lastMessageDate = channel.lastMessageDate // lastMessageDate = channel.lastMessageDate
created = channel.created // created = channel.created
deleted = channel.deleted // deleted = channel.deleted
createdBy = channel.createdBy // createdBy = channel.createdBy
config = channel.config // config = channel.config
frozen = channel.frozen // frozen = channel.frozen
extraData = channel.extraData // extraData = channel.extraData
} // }
//
/// A channel id. // /// A channel id.
public let id: String // public let id: String
/// A channel type + id. // /// A channel type + id.
public let cid: ChannelId // public let cid: ChannelId
/// A channel type. // /// A channel type.
public let type: ChannelType // public let type: ChannelType
/// A channel name. // /// A channel name.
public let name: String? // public let name: String?
/// An image of the channel. // /// An image of the channel.
public let imageURL: URL? // public let imageURL: URL?
/// The last message date. // /// The last message date.
public let lastMessageDate: Date? // public let lastMessageDate: Date?
/// A channel created date. // /// A channel created date.
public let created: Date // public let created: Date
/// A channel deleted date. // /// A channel deleted date.
public let deleted: Date? // public let deleted: Date?
/// A creator of the channel. // /// A creator of the channel.
public let createdBy: User? // public let createdBy: User?
/// A config. // /// A config.
public let config: Channel.Config // public let config: Channel.Config
/// Checks if the channel is frozen. // /// Checks if the channel is frozen.
public let frozen: Bool // public let frozen: Bool
/// A list of user ids of the channel members. // /// A list of user ids of the channel members.
public let members = Set<Member>() // public let members = Set<Member>()
/// An extra data for the channel. // /// An extra data for the channel.
public let extraData: Codable? // public let extraData: Codable?
} //}
+16 -63
View File
@@ -10,81 +10,34 @@ project 'Runner', {
'Release' => :release, 'Release' => :release,
} }
def parse_KV_file(file, separator='=') def flutter_root
file_abs_path = File.expand_path(file) generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
if !File.exists? file_abs_path unless File.exist?(generated_xcode_build_settings_path)
return []; raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end end
generated_key_values = {}
skip_line_start_symbols = ["#", "/"] File.foreach(generated_xcode_build_settings_path) do |line|
File.foreach(file_abs_path) do |line| matches = line.match(/FLUTTER_ROOT\=(.*)/)
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } return matches[1].strip if matches
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
generated_key_values[podname] = podpath
else
puts "Invalid plugin specification: #{line}"
end
end end
generated_key_values raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do target 'Runner' do
use_frameworks! use_frameworks!
use_modular_headers! use_modular_headers!
# Flutter Pod
copied_flutter_dir = File.join(__dir__, 'Flutter') flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
# Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
# That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
# CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
unless File.exist?(generated_xcode_build_settings_path)
raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
unless File.exist?(copied_framework_path)
FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
end
unless File.exist?(copied_podspec_path)
FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
end
end
# Keep pod path relative so it can be checked into Podfile.lock.
pod 'Flutter', :path => 'Flutter'
pod 'StreamChatClient', '~> 2.0.0'
# Plugin Pods
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.each do |name, path|
symlink = File.join('.symlinks', 'plugins', name)
File.symlink(path, symlink)
pod name, :path => File.join(symlink, 'ios')
end
end end
# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. pod 'StreamChatClient'
install! 'cocoapods', :disable_input_output_paths => true
post_install do |installer| post_install do |installer|
installer.pods_project.targets.each do |target| installer.pods_project.targets.each do |target|
target.build_configurations.each do |config| flutter_additional_ios_build_settings(target)
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end end
end end
+106 -164
View File
@@ -33,53 +33,49 @@ PODS:
- file_picker (0.0.1): - file_picker (0.0.1):
- DKImagePickerController/PhotoGallery - DKImagePickerController/PhotoGallery
- Flutter - Flutter
- Firebase/Core (6.28.1): - Firebase/CoreOnly (6.26.0):
- FirebaseCore (= 6.7.2)
- Firebase/Messaging (6.26.0):
- Firebase/CoreOnly - Firebase/CoreOnly
- FirebaseAnalytics (= 6.6.2) - FirebaseMessaging (~> 4.4.1)
- Firebase/CoreOnly (6.28.1): - firebase_core (0.5.0):
- FirebaseCore (= 6.9.1) - Firebase/CoreOnly (~> 6.26.0)
- Firebase/Messaging (6.28.1):
- Firebase/CoreOnly
- FirebaseMessaging (~> 4.6.0)
- firebase_messaging (0.0.1):
- Firebase/Core
- Firebase/Messaging
- Flutter - Flutter
- FirebaseAnalytics (6.6.2): - firebase_messaging (7.0.2):
- FirebaseCore (~> 6.8) - Firebase/CoreOnly (~> 6.26.0)
- FirebaseInstallations (~> 1.4) - Firebase/Messaging (~> 6.26.0)
- GoogleAppMeasurement (= 6.6.2) - firebase_core
- GoogleUtilities/AppDelegateSwizzler (~> 6.0) - Flutter
- GoogleUtilities/MethodSwizzler (~> 6.0) - FirebaseAnalyticsInterop (1.5.0)
- GoogleUtilities/Network (~> 6.0) - FirebaseCore (6.7.2):
- "GoogleUtilities/NSData+zlib (~> 6.0)"
- nanopb (~> 1.30905.0)
- FirebaseCore (6.9.1):
- FirebaseCoreDiagnostics (~> 1.3) - FirebaseCoreDiagnostics (~> 1.3)
- FirebaseCoreDiagnosticsInterop (~> 1.2)
- GoogleUtilities/Environment (~> 6.5)
- GoogleUtilities/Logger (~> 6.5)
- FirebaseCoreDiagnostics (1.7.0):
- GoogleDataTransport (~> 7.4)
- GoogleUtilities/Environment (~> 6.7) - GoogleUtilities/Environment (~> 6.7)
- GoogleUtilities/Logger (~> 6.7) - GoogleUtilities/Logger (~> 6.7)
- FirebaseCoreDiagnostics (1.5.0): - nanopb (~> 1.30906.0)
- GoogleDataTransport (~> 7.0) - FirebaseCoreDiagnosticsInterop (1.2.0)
- GoogleUtilities/Environment (~> 6.7) - FirebaseInstallations (1.3.0):
- GoogleUtilities/Logger (~> 6.7) - FirebaseCore (~> 6.6)
- nanopb (~> 1.30905.0) - GoogleUtilities/Environment (~> 6.6)
- FirebaseInstallations (1.5.0): - GoogleUtilities/UserDefaults (~> 6.6)
- FirebaseCore (~> 6.8)
- GoogleUtilities/Environment (~> 6.7)
- GoogleUtilities/UserDefaults (~> 6.7)
- PromisesObjC (~> 1.2) - PromisesObjC (~> 1.2)
- FirebaseInstanceID (4.5.0): - FirebaseInstanceID (4.3.4):
- FirebaseCore (~> 6.8) - FirebaseCore (~> 6.6)
- FirebaseInstallations (~> 1.0) - FirebaseInstallations (~> 1.0)
- GoogleUtilities/Environment (~> 6.7) - GoogleUtilities/Environment (~> 6.5)
- GoogleUtilities/UserDefaults (~> 6.7) - GoogleUtilities/UserDefaults (~> 6.5)
- FirebaseMessaging (4.6.0): - FirebaseMessaging (4.4.1):
- FirebaseCore (~> 6.8) - FirebaseAnalyticsInterop (~> 1.5)
- FirebaseCore (~> 6.6)
- FirebaseInstanceID (~> 4.3) - FirebaseInstanceID (~> 4.3)
- GoogleUtilities/AppDelegateSwizzler (~> 6.7) - GoogleUtilities/AppDelegateSwizzler (~> 6.5)
- GoogleUtilities/Environment (~> 6.7) - GoogleUtilities/Environment (~> 6.5)
- GoogleUtilities/Reachability (~> 6.7) - GoogleUtilities/Reachability (~> 6.5)
- GoogleUtilities/UserDefaults (~> 6.7) - GoogleUtilities/UserDefaults (~> 6.5)
- Protobuf (>= 3.9.2, ~> 3.9) - Protobuf (>= 3.9.2, ~> 3.9)
- Flutter (1.0.0) - Flutter (1.0.0)
- flutter_apns (0.0.1): - flutter_apns (0.0.1):
@@ -88,117 +84,92 @@ PODS:
- Flutter - Flutter
- flutter_local_notifications (0.0.1): - flutter_local_notifications (0.0.1):
- Flutter - Flutter
- flutter_plugin_android_lifecycle (0.0.1):
- Flutter
- FMDB (2.7.5): - FMDB (2.7.5):
- FMDB/standard (= 2.7.5) - FMDB/standard (= 2.7.5)
- FMDB/standard (2.7.5) - FMDB/standard (2.7.5)
- GoogleAppMeasurement (6.6.2): - GoogleDataTransport (7.4.0):
- GoogleUtilities/AppDelegateSwizzler (~> 6.0) - nanopb (~> 1.30906.0)
- GoogleUtilities/MethodSwizzler (~> 6.0) - GoogleUtilities/AppDelegateSwizzler (6.7.2):
- GoogleUtilities/Network (~> 6.0)
- "GoogleUtilities/NSData+zlib (~> 6.0)"
- nanopb (~> 1.30905.0)
- GoogleDataTransport (7.0.0):
- nanopb (~> 1.30905.0)
- GoogleUtilities/AppDelegateSwizzler (6.7.1):
- GoogleUtilities/Environment - GoogleUtilities/Environment
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GoogleUtilities/Network - GoogleUtilities/Network
- GoogleUtilities/Environment (6.7.1): - GoogleUtilities/Environment (6.7.2):
- PromisesObjC (~> 1.2) - PromisesObjC (~> 1.2)
- GoogleUtilities/Logger (6.7.1): - GoogleUtilities/Logger (6.7.2):
- GoogleUtilities/Environment - GoogleUtilities/Environment
- GoogleUtilities/MethodSwizzler (6.7.1): - GoogleUtilities/Network (6.7.2):
- GoogleUtilities/Logger
- GoogleUtilities/Network (6.7.1):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib" - "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Reachability - GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (6.7.1)" - "GoogleUtilities/NSData+zlib (6.7.2)"
- GoogleUtilities/Reachability (6.7.1): - GoogleUtilities/Reachability (6.7.2):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (6.7.1): - GoogleUtilities/UserDefaults (6.7.2):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GzipSwift (5.1.1)
- image_picker (0.0.1): - image_picker (0.0.1):
- Flutter - Flutter
- moor_ffi (0.0.1): - nanopb (1.30906.0):
- Flutter - nanopb/decode (= 1.30906.0)
- nanopb (1.30905.0): - nanopb/encode (= 1.30906.0)
- nanopb/decode (= 1.30905.0) - nanopb/decode (1.30906.0)
- nanopb/encode (= 1.30905.0) - nanopb/encode (1.30906.0)
- nanopb/decode (1.30905.0)
- nanopb/encode (1.30905.0)
- path_provider (0.0.1): - path_provider (0.0.1):
- Flutter - Flutter
- path_provider_linux (0.0.1): - PromisesObjC (1.2.10)
- Flutter - Protobuf (3.13.0)
- path_provider_macos (0.0.1): - SDWebImage (5.9.2):
- Flutter - SDWebImage/Core (= 5.9.2)
- PromisesObjC (1.2.9) - SDWebImage/Core (5.9.2)
- Protobuf (3.12.0)
- ReachabilitySwift (5.0.0)
- SDWebImage (5.8.4):
- SDWebImage/Core (= 5.8.4)
- SDWebImage/Core (5.8.4)
- shared_preferences (0.0.1): - shared_preferences (0.0.1):
- Flutter - Flutter
- shared_preferences_linux (0.0.1):
- Flutter
- shared_preferences_macos (0.0.1):
- Flutter
- shared_preferences_web (0.0.1):
- Flutter
- sqflite (0.0.1): - sqflite (0.0.1):
- Flutter - Flutter
- FMDB (~> 2.7.2) - FMDB (~> 2.7.2)
- Starscream (3.1.1) - sqlite3 (3.32.3):
- StreamChatClient (2.0.1): - sqlite3/common (= 3.32.3)
- GzipSwift (~> 5.1) - sqlite3/common (3.32.3)
- ReachabilitySwift (~> 5.0) - sqlite3/fts5 (3.32.3):
- Starscream (~> 3.1) - 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.0):
- Starscream (~> 4.0)
- SwiftyGif (5.3.0) - SwiftyGif (5.3.0)
- url_launcher (0.0.1): - url_launcher (0.0.1):
- Flutter - Flutter
- url_launcher_linux (0.0.1):
- Flutter
- url_launcher_macos (0.0.1):
- Flutter
- url_launcher_web (0.0.1):
- Flutter
- video_player (0.0.1): - video_player (0.0.1):
- Flutter - Flutter
- video_player_web (0.0.1):
- Flutter
- wakelock (0.0.1): - wakelock (0.0.1):
- Flutter - Flutter
DEPENDENCIES: DEPENDENCIES:
- file_picker (from `.symlinks/plugins/file_picker/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`) - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
- flutter_apns (from `.symlinks/plugins/flutter_apns/ios`) - flutter_apns (from `.symlinks/plugins/flutter_apns/ios`)
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`) - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- flutter_plugin_android_lifecycle (from `.symlinks/plugins/flutter_plugin_android_lifecycle/ios`)
- image_picker (from `.symlinks/plugins/image_picker/ios`) - image_picker (from `.symlinks/plugins/image_picker/ios`)
- moor_ffi (from `.symlinks/plugins/moor_ffi/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`) - path_provider (from `.symlinks/plugins/path_provider/ios`)
- path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`)
- path_provider_macos (from `.symlinks/plugins/path_provider_macos/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- shared_preferences_linux (from `.symlinks/plugins/shared_preferences_linux/ios`)
- shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`)
- shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`)
- StreamChatClient (~> 2.0.0) - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`)
- StreamChatClient
- url_launcher (from `.symlinks/plugins/url_launcher/ios`) - url_launcher (from `.symlinks/plugins/url_launcher/ios`)
- url_launcher_linux (from `.symlinks/plugins/url_launcher_linux/ios`)
- url_launcher_macos (from `.symlinks/plugins/url_launcher_macos/ios`)
- url_launcher_web (from `.symlinks/plugins/url_launcher_web/ios`)
- video_player (from `.symlinks/plugins/video_player/ios`) - video_player (from `.symlinks/plugins/video_player/ios`)
- video_player_web (from `.symlinks/plugins/video_player_web/ios`)
- wakelock (from `.symlinks/plugins/wakelock/ios`) - wakelock (from `.symlinks/plugins/wakelock/ios`)
SPEC REPOS: SPEC REPOS:
@@ -206,22 +177,21 @@ SPEC REPOS:
- DKImagePickerController - DKImagePickerController
- DKPhotoGallery - DKPhotoGallery
- Firebase - Firebase
- FirebaseAnalytics - FirebaseAnalyticsInterop
- FirebaseCore - FirebaseCore
- FirebaseCoreDiagnostics - FirebaseCoreDiagnostics
- FirebaseCoreDiagnosticsInterop
- FirebaseInstallations - FirebaseInstallations
- FirebaseInstanceID - FirebaseInstanceID
- FirebaseMessaging - FirebaseMessaging
- FMDB - FMDB
- GoogleAppMeasurement
- GoogleDataTransport - GoogleDataTransport
- GoogleUtilities - GoogleUtilities
- GzipSwift
- nanopb - nanopb
- PromisesObjC - PromisesObjC
- Protobuf - Protobuf
- ReachabilitySwift
- SDWebImage - SDWebImage
- sqlite3
- Starscream - Starscream
- StreamChatClient - StreamChatClient
- SwiftyGif - SwiftyGif
@@ -229,6 +199,8 @@ SPEC REPOS:
EXTERNAL SOURCES: EXTERNAL SOURCES:
file_picker: file_picker:
:path: ".symlinks/plugins/file_picker/ios" :path: ".symlinks/plugins/file_picker/ios"
firebase_core:
:path: ".symlinks/plugins/firebase_core/ios"
firebase_messaging: firebase_messaging:
:path: ".symlinks/plugins/firebase_messaging/ios" :path: ".symlinks/plugins/firebase_messaging/ios"
Flutter: Flutter:
@@ -239,40 +211,20 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios" :path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
flutter_local_notifications: flutter_local_notifications:
:path: ".symlinks/plugins/flutter_local_notifications/ios" :path: ".symlinks/plugins/flutter_local_notifications/ios"
flutter_plugin_android_lifecycle:
:path: ".symlinks/plugins/flutter_plugin_android_lifecycle/ios"
image_picker: image_picker:
:path: ".symlinks/plugins/image_picker/ios" :path: ".symlinks/plugins/image_picker/ios"
moor_ffi:
:path: ".symlinks/plugins/moor_ffi/ios"
path_provider: path_provider:
:path: ".symlinks/plugins/path_provider/ios" :path: ".symlinks/plugins/path_provider/ios"
path_provider_linux:
:path: ".symlinks/plugins/path_provider_linux/ios"
path_provider_macos:
:path: ".symlinks/plugins/path_provider_macos/ios"
shared_preferences: shared_preferences:
:path: ".symlinks/plugins/shared_preferences/ios" :path: ".symlinks/plugins/shared_preferences/ios"
shared_preferences_linux:
:path: ".symlinks/plugins/shared_preferences_linux/ios"
shared_preferences_macos:
:path: ".symlinks/plugins/shared_preferences_macos/ios"
shared_preferences_web:
:path: ".symlinks/plugins/shared_preferences_web/ios"
sqflite: sqflite:
:path: ".symlinks/plugins/sqflite/ios" :path: ".symlinks/plugins/sqflite/ios"
sqlite3_flutter_libs:
:path: ".symlinks/plugins/sqlite3_flutter_libs/ios"
url_launcher: url_launcher:
:path: ".symlinks/plugins/url_launcher/ios" :path: ".symlinks/plugins/url_launcher/ios"
url_launcher_linux:
:path: ".symlinks/plugins/url_launcher_linux/ios"
url_launcher_macos:
:path: ".symlinks/plugins/url_launcher_macos/ios"
url_launcher_web:
:path: ".symlinks/plugins/url_launcher_web/ios"
video_player: video_player:
:path: ".symlinks/plugins/video_player/ios" :path: ".symlinks/plugins/video_player/ios"
video_player_web:
:path: ".symlinks/plugins/video_player_web/ios"
wakelock: wakelock:
:path: ".symlinks/plugins/wakelock/ios" :path: ".symlinks/plugins/wakelock/ios"
@@ -280,50 +232,40 @@ SPEC CHECKSUMS:
DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
Firebase: ed042590caa0029392257529a8003c25ee82bc18 Firebase: 7cf5f9c67f03cb3b606d1d6535286e1080e57eb6
firebase_messaging: 21344b3b3a7d9d325d63a70e3750c0c798fe1e03 firebase_core: 3134fe79d257d430f163b558caf52a10a87efe8a
FirebaseAnalytics: 5fa308e1b13f838d0f6dc74719ac2a72e8c5afc4 firebase_messaging: 2844c37f9ce87c0904b38fe435223161b1a71528
FirebaseCore: 687b8e6a0a4337b898a6326d68254c2f80c143af FirebaseAnalyticsInterop: 3f86269c38ae41f47afeb43ebf32a001f58fcdae
FirebaseCoreDiagnostics: 7535fe695737f8c5b350584292a70b7f8ff0357b FirebaseCore: f42e5e5f382cdcf6b617ed737bf6c871a6947b17
FirebaseInstallations: 3c520c951305cbf9ca54eb891ff9e6d1fd384881 FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1
FirebaseInstanceID: 358d5cb393d2750a745569ede06827c35aea530b FirebaseCoreDiagnosticsInterop: 296e2c5f5314500a850ad0b83e9e7c10b011a850
FirebaseMessaging: bdd4d573eab37ebee29bad4e7c4b0ef18fa1a952 FirebaseInstallations: 6f5f680e65dc374397a483c32d1799ba822a395b
FirebaseInstanceID: cef67c4967c7cecb56ea65d8acbb4834825c587b
FirebaseMessaging: 29543feb343b09546ab3aa04d008ee8595b43c44
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
flutter_apns: f516b118e423fe7c0a38771180549c4d6cb67c2f flutter_apns: f516b118e423fe7c0a38771180549c4d6cb67c2f
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
flutter_local_notifications: 9e4738ce2471c5af910d961a6b7eadcf57c50186 flutter_local_notifications: 9e4738ce2471c5af910d961a6b7eadcf57c50186
flutter_plugin_android_lifecycle: dc0b544e129eebb77a6bfb1239d4d1c673a60a35
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
GoogleAppMeasurement: 8cd1f289d60e629cf16ab03363b9e89c776b9651 GoogleDataTransport: b7f406340a291370045a270c599e53c6fa6ec20f
GoogleDataTransport: 8a40cb194ad242b6f6dfe72c14fe40fc67c4dcd7 GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
GoogleUtilities: e121a3867449ce16b0e35ddf1797ea7a389ffdf2
GzipSwift: 893f3e48e597a1a4f62fafcb6514220fcf8287fa
image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09 image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09
moor_ffi: d66c9470c18e9cb333423bbcb493c105c6c774c6 nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
nanopb: c43f40fadfe79e8b8db116583945847910cbabc9
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4 PromisesObjC: b14b1c6b68e306650688599de8a45e49fae81151
path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0 Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748
PromisesObjC: b48e0338dbbac2207e611750777895f7a5811b75 SDWebImage: 0b42b8719ab0c5257177d5894306e8a336b21cbb
Protobuf: 2793fcd0622a00b546c60e7cbbcc493e043e9bb9
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
SDWebImage: cf6922231e95550934da2ada0f20f2becf2ceba9
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
shared_preferences_linux: afefbfe8d921e207f01ede8b60373d9e3b566b78
shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087
shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9
sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0 sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0
Starscream: 4bb2f9942274833f7b4d296a55504dcfc7edb7b0 sqlite3: 8f7d2078ae27778699a622a94b853285793422a2
StreamChatClient: 91b0f585e7dc92ade58e657daffafb16d485b2a6 sqlite3_flutter_libs: 5651f8ff48e3b44d910863c4ea5916085b1b245f
Starscream: 5178aed56b316f13fa3bc55694e583d35dd414d9
StreamChatClient: 8c83a141e753e45fa096ff56d4b782d59e46f251
SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40 SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
url_launcher_linux: ac237cb7a8058736e4aae38bdbcc748a4b394cc0
url_launcher_macos: fd7894421cd39320dce5f292fc99ea9270b2a313
url_launcher_web: e5527357f037c87560776e36436bf2b0288b965c
video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e
video_player_web: da8cadb8274ed4f8dbee8d7171b420dedd437ce7
wakelock: 0d4a70faf8950410735e3f61fb15d517c8a6efc4 wakelock: 0d4a70faf8950410735e3f61fb15d517c8a6efc4
PODFILE CHECKSUM: aaaddd91b568e9a010ff3278737eb06bc017bd6e PODFILE CHECKSUM: eb001256612a59f8f9e4d083ad8b9671e69dd184
COCOAPODS: 1.8.4 COCOAPODS: 1.8.4
+51 -3
View File
@@ -308,9 +308,60 @@
files = ( files = (
); );
inputPaths = ( 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}/file_picker/file_picker.framework",
"${BUILT_PRODUCTS_DIR}/flutter_apns/flutter_apns.framework",
"${BUILT_PRODUCTS_DIR}/flutter_keyboard_visibility/flutter_keyboard_visibility.framework",
"${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.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}/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_player/video_player.framework",
"${BUILT_PRODUCTS_DIR}/wakelock/wakelock.framework",
); );
name = "[CP] Embed Pods Frameworks"; name = "[CP] Embed Pods Frameworks";
outputPaths = ( 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}/file_picker.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_apns.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}/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}/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_player.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock.framework",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
@@ -489,7 +540,6 @@
}; };
249021D3217E4FDB00AE95B9 /* Profile */ = { 249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
@@ -573,7 +623,6 @@
}; };
97C147031CF9000F007C117D /* Debug */ = { 97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
@@ -629,7 +678,6 @@
}; };
97C147041CF9000F007C117D /* Release */ = { 97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
+194
View File
@@ -110,6 +110,14 @@ class ChannelListPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return CreateChannelPage();
}));
},
),
body: ChannelsBloc( body: ChannelsBloc(
child: ChannelListView( child: ChannelListView(
swipeToAction: true, swipeToAction: true,
@@ -204,3 +212,189 @@ class ThreadPage extends StatelessWidget {
); );
} }
} }
class CreateChannelPage extends StatefulWidget {
@override
_CreateChannelPageState createState() => _CreateChannelPageState();
}
class _CreateChannelPageState extends State<CreateChannelPage> {
final ScrollController _scrollController = ScrollController();
Client client;
List<User> users = [];
List<User> selectedUsers = [];
int offset = 0;
bool loading = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
title: Text(
'Create a channel',
style: Theme.of(context).textTheme.headline6,
),
),
floatingActionButton:
selectedUsers.isNotEmpty ? _buildFAB(context) : SizedBox(),
body: _buildListView(),
);
}
ListView _buildListView() {
return ListView.builder(
controller: _scrollController,
itemBuilder: _itemBuilder,
itemCount: users.length,
);
}
Widget _itemBuilder(context, i) {
final user = users[i];
return ListTile(
onLongPress: () {
_selectUser(user);
},
selected: selectedUsers.contains(user),
onTap: () {
if (selectedUsers.isNotEmpty) {
return _selectUser(user);
}
_createChannel(context, [user]);
},
leading: UserAvatar(
user: user,
),
title: Text(user.name),
);
}
Widget _buildFAB(BuildContext context) {
return FloatingActionButton(
child: Icon(Icons.done),
onPressed: () async {
String name;
if (selectedUsers.length > 1) {
name = await _showEnterNameDialog(context);
if (name?.isNotEmpty != true) {
return;
}
}
_createChannel(context, selectedUsers, name);
},
);
}
Future<String> _showEnterNameDialog(BuildContext context) {
final controller = TextEditingController();
return showDialog(
context: context,
builder: (context) => SimpleDialog(
contentPadding: const EdgeInsets.all(16),
title: Text('Enter a name for the channel'),
children: [
TextField(
controller: controller,
decoration: InputDecoration(
border: OutlineInputBorder(),
),
),
ButtonBar(
children: [
FlatButton(
onPressed: () => Navigator.pop(context),
child: Text('Cancel'),
),
FlatButton(
onPressed: () => Navigator.pop(context, controller.text),
child: Text('Ok'),
),
],
),
],
),
);
}
Future _createChannel(
BuildContext context,
List<User> users, [
String name,
]) async {
final channel = client.channel('messaging', extraData: {
'members': [
client.state.user.id,
...users.map((e) => e.id),
],
if (name != null) 'name': name,
});
await channel.watch();
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) {
return StreamChannel(
child: ChannelPage(),
channel: channel,
);
},
),
);
}
void _selectUser(User user) {
if (!selectedUsers.contains(user)) {
setState(() {
selectedUsers.add(user);
});
} else {
setState(() {
selectedUsers.remove(user);
});
}
}
@override
void initState() {
super.initState();
client = StreamChat.of(context).client;
_scrollController.addListener(() async {
if (!loading &&
_scrollController.offset >=
_scrollController.position.maxScrollExtent - 100) {
offset += 25;
await _queryUsers();
}
});
_queryUsers();
}
Future<void> _queryUsers() {
loading = true;
return client.queryUsers(
pagination: PaginationParams(
limit: 25,
offset: offset,
),
sort: [
SortOption(
'name',
direction: SortOption.ASC,
),
],
).then((value) {
setState(() {
users = [
...users,
...value.users,
];
});
}).whenComplete(() => loading = false);
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
name: example name: example
description: A new Flutter project. description: A new Flutter project.
version: 1.0.13+15 version: 1.0.14+16
environment: environment:
sdk: ">=2.2.2 <3.0.0" sdk: ">=2.2.2 <3.0.0"
+1 -1
View File
@@ -78,7 +78,7 @@ class ChannelImage extends StatelessWidget {
String image; String image;
if (snapshot.data?.containsKey('image') == true) { if (snapshot.data?.containsKey('image') == true) {
image = snapshot.data['image']; image = snapshot.data['image'];
} else if (channel.state.members.length == 2) { } else if (channel.state.members?.length == 2) {
final otherMember = channel.state.members final otherMember = channel.state.members
.firstWhere((member) => member.user.id != streamChat.user.id); .firstWhere((member) => member.user.id != streamChat.user.id);
return StreamBuilder<User>( return StreamBuilder<User>(
+128 -83
View File
@@ -66,6 +66,7 @@ class ChannelListView extends StatefulWidget {
this.errorBuilder, this.errorBuilder,
this.onImageTap, this.onImageTap,
this.swipeToAction = false, this.swipeToAction = false,
this.pullToRefresh = true,
}) : super(key: key); }) : super(key: key);
/// The builder that will be used in case of error /// The builder that will be used in case of error
@@ -114,6 +115,9 @@ class ChannelListView extends StatefulWidget {
/// The function called when the image is tapped /// The function called when the image is tapped
final Function(Channel) onImageTap; final Function(Channel) onImageTap;
/// Set it to false to disable the pull-to-refresh widget
final bool pullToRefresh;
@override @override
_ChannelListViewState createState() => _ChannelListViewState(); _ChannelListViewState createState() => _ChannelListViewState();
} }
@@ -124,105 +128,146 @@ class _ChannelListViewState extends State<ChannelListView>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final channelsProvider = ChannelsBloc.of(context); final channelsBloc = ChannelsBloc.of(context);
if (!widget.pullToRefresh) {
return _buildListView(channelsBloc);
}
return RefreshIndicator( return RefreshIndicator(
onRefresh: () async { onRefresh: () async {
return channelsProvider.queryChannels( return channelsBloc.queryChannels(
filter: widget.filter, filter: widget.filter,
sortOptions: widget.sort, sortOptions: widget.sort,
paginationParams: widget.pagination, paginationParams: widget.pagination,
options: widget.options, options: widget.options,
); );
}, },
child: StreamBuilder<List<Channel>>( child: _buildListView(channelsBloc),
stream: channelsProvider.channelsStream, );
builder: (context, snapshot) { }
if (snapshot.hasError) {
if (snapshot.error is Error) {
print((snapshot.error as Error).stackTrace);
}
if (widget.errorBuilder != null) { StreamBuilder<List<Channel>> _buildListView(
return widget.errorBuilder(snapshot.error); ChannelsBlocState channelsBlocState,
} ) {
return StreamBuilder<List<Channel>>(
stream: channelsBlocState.channelsStream,
builder: (context, snapshot) {
if (snapshot.hasError) {
if (snapshot.error is Error) {
print((snapshot.error as Error).stackTrace);
}
var message = snapshot.error.toString(); if (widget.errorBuilder != null) {
if (snapshot.error is DioError) { return widget.errorBuilder(snapshot.error);
final dioError = snapshot.error as DioError; }
if (dioError.type == DioErrorType.RESPONSE) {
message = dioError.message; var message = snapshot.error.toString();
} else { if (snapshot.error is DioError) {
message = 'Check your connection and retry'; final dioError = snapshot.error as DioError;
} if (dioError.type == DioErrorType.RESPONSE) {
message = dioError.message;
} else {
message = 'Check your connection and retry';
} }
return Center( }
child: Column( return Center(
mainAxisAlignment: MainAxisAlignment.center, child: Column(
children: <Widget>[ mainAxisAlignment: MainAxisAlignment.center,
Text.rich( children: <Widget>[
TextSpan( Text.rich(
children: [ TextSpan(
WidgetSpan( children: [
child: Padding( WidgetSpan(
padding: const EdgeInsets.only( child: Padding(
right: 2.0, padding: const EdgeInsets.only(
), right: 2.0,
child: Icon(Icons.error_outline),
), ),
child: Icon(Icons.error_outline),
), ),
TextSpan(text: 'Error loading channels'), ),
], TextSpan(text: 'Error loading channels'),
), ],
style: Theme.of(context).textTheme.headline6,
), ),
Padding( style: Theme.of(context).textTheme.headline6,
padding: const EdgeInsets.only( ),
top: 16.0, Padding(
), padding: const EdgeInsets.only(
child: Text(message), top: 16.0,
), ),
FlatButton( child: Text(message),
onPressed: () { ),
channelsProvider.queryChannels( FlatButton(
filter: widget.filter, onPressed: () {
sortOptions: widget.sort, channelsBlocState.queryChannels(
paginationParams: widget.pagination, filter: widget.filter,
options: widget.options, sortOptions: widget.sort,
); paginationParams: widget.pagination,
}, options: widget.options,
child: Text('Retry'), );
), },
], child: Text('Retry'),
), ),
); ],
}
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
final channels = snapshot.data;
return ListView.custom(
physics: AlwaysScrollableScrollPhysics(),
controller: _scrollController,
childrenDelegate: SliverChildBuilderDelegate(
(context, i) {
return _itemBuilder(context, i, channels);
},
childCount: (channels.length * 2) + 1,
findChildIndexCallback: (key) {
final ValueKey<String> valueKey = key;
final index = channels.indexWhere(
(channel) => 'CHANNEL-${channel.id}' == valueKey.value);
return index != -1 ? (index * 2) : null;
},
), ),
); );
}), }
);
if (!snapshot.hasData) {
return LayoutBuilder(
builder: (context, viewportConstraints) {
return SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Center(
child: CircularProgressIndicator(),
),
),
);
},
);
}
final channels = snapshot.data;
if (channels.isEmpty) {
return LayoutBuilder(
builder: (context, viewportConstraints) {
return SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Center(
child: Text('You have no channels currently'),
),
),
);
},
);
}
return ListView.custom(
physics: AlwaysScrollableScrollPhysics(),
controller: _scrollController,
childrenDelegate: SliverChildBuilderDelegate(
(context, i) {
return _itemBuilder(context, i, channels);
},
childCount: (channels.length * 2) + 1,
findChildIndexCallback: (key) {
final ValueKey<String> valueKey = key;
final index = channels.indexWhere(
(channel) => 'CHANNEL-${channel.id}' == valueKey.value);
return index != -1 ? (index * 2) : null;
},
),
);
});
} }
Widget _itemBuilder(context, int i, List<Channel> channels) { Widget _itemBuilder(context, int i, List<Channel> channels) {
@@ -430,7 +475,7 @@ class _ChannelListViewState extends State<ChannelListView>
filter: widget.filter, filter: widget.filter,
sortOptions: widget.sort, sortOptions: widget.sort,
paginationParams: widget.pagination.copyWith( paginationParams: widget.pagination.copyWith(
offset: channelsProvider.channels.length, offset: channelsProvider.channels?.length ?? 0,
), ),
options: widget.options, options: widget.options,
); );
@@ -482,7 +527,7 @@ class _ChannelListViewState extends State<ChannelListView>
void didUpdateWidget(ChannelListView oldWidget) { void didUpdateWidget(ChannelListView oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (widget.filter != oldWidget.filter || if (widget.filter?.toString() != oldWidget.filter?.toString() ||
widget.sort != oldWidget.sort || widget.sort != oldWidget.sort ||
widget.pagination != oldWidget.pagination || widget.pagination != oldWidget.pagination ||
widget.options != oldWidget.options) { widget.options != oldWidget.options) {
+25 -19
View File
@@ -11,7 +11,7 @@ class ChannelsBloc extends StatefulWidget {
/// The widget child /// The widget child
final Widget child; final Widget child;
/// Set this to false to prevent channels to be brought to the top of the list when a new message arrives /// Set this to true to prevent channels to be brought to the top of the list when a new message arrives
final bool lockChannelsOrder; final bool lockChannelsOrder;
/// Instantiate a new ChannelsBloc /// Instantiate a new ChannelsBloc
@@ -56,8 +56,7 @@ class ChannelsBlocState extends State<ChannelsBloc>
final BehaviorSubject<bool> _queryChannelsLoadingController = final BehaviorSubject<bool> _queryChannelsLoadingController =
BehaviorSubject.seeded(false); BehaviorSubject.seeded(false);
final BehaviorSubject<List<Channel>> _channelsController = final BehaviorSubject<List<Channel>> _channelsController = BehaviorSubject();
BehaviorSubject.seeded([]);
/// The stream notifying the state of queryChannel call /// The stream notifying the state of queryChannel call
Stream<bool> get queryChannelsLoading => Stream<bool> get queryChannelsLoading =>
@@ -73,7 +72,10 @@ class ChannelsBlocState extends State<ChannelsBloc>
Map<String, dynamic> options, Map<String, dynamic> options,
bool onlyOffline = false, bool onlyOffline = false,
}) async { }) async {
if (_queryChannelsLoadingController.value == true) { final client = StreamChat.of(context).client;
if (client.state?.user == null ||
_queryChannelsLoadingController.value == true) {
return; return;
} }
_queryChannelsLoadingController.sink.add(true); _queryChannelsLoadingController.sink.add(true);
@@ -82,16 +84,15 @@ class ChannelsBlocState extends State<ChannelsBloc>
final clear = paginationParams == null || final clear = paginationParams == null ||
paginationParams.offset == null || paginationParams.offset == null ||
paginationParams.offset == 0; paginationParams.offset == 0;
final oldChannels = List<Channel>.from(channels); final oldChannels = List<Channel>.from(channels ?? []);
StreamChat.of(context) client
.client
.queryChannels( .queryChannels(
filter: filter, filter: filter,
sort: sortOptions, sort: sortOptions,
options: options, options: options,
paginationParams: paginationParams, paginationParams: paginationParams,
onlyOffline: onlyOffline, onlyOffline: onlyOffline,
) )
.listen((channels) { .listen((channels) {
if (clear) { if (clear) {
_channelsController.add(channels); _channelsController.add(channels);
@@ -123,23 +124,28 @@ class ChannelsBlocState extends State<ChannelsBloc>
_subscriptions.add(client.on(EventType.messageNew).listen((e) { _subscriptions.add(client.on(EventType.messageNew).listen((e) {
final newChannels = List<Channel>.from(channels ?? []); final newChannels = List<Channel>.from(channels ?? []);
final index = newChannels.indexWhere((c) => c.cid == e.cid); final index = newChannels.indexWhere((c) => c.cid == e.cid);
if (index > 0) { if (index > -1) {
final channel = newChannels.removeAt(index); if (index > 0) {
newChannels.insert(0, channel); final channel = newChannels.removeAt(index);
_channelsController.add(newChannels); newChannels.insert(0, channel);
}
} else { } else {
final hiddenIndex = _hiddenChannels.indexWhere((c) => c.cid == e.cid); final hiddenIndex = _hiddenChannels.indexWhere((c) => c.cid == e.cid);
if (hiddenIndex > -1) { if (hiddenIndex > -1) {
newChannels.insert(0, _hiddenChannels[hiddenIndex]); newChannels.insert(0, _hiddenChannels[hiddenIndex]);
_hiddenChannels.removeAt(hiddenIndex); _hiddenChannels.removeAt(hiddenIndex);
_channelsController.add(newChannels); } else {
if (client.state.channels[e.cid] != null) {
newChannels.insert(0, client.state.channels[e.cid]);
}
} }
} }
_channelsController.add(newChannels);
})); }));
} }
_subscriptions.add(client.on(EventType.channelHidden).listen((event) async { _subscriptions.add(client.on(EventType.channelHidden).listen((event) async {
final newChannels = List<Channel>.from(channels); final newChannels = List<Channel>.from(channels ?? []);
final channelIndex = newChannels.indexWhere((c) => c.cid == event.cid); final channelIndex = newChannels.indexWhere((c) => c.cid == event.cid);
if (channelIndex > -1) { if (channelIndex > -1) {
final channel = newChannels.removeAt(channelIndex); final channel = newChannels.removeAt(channelIndex);
+14 -6
View File
@@ -15,12 +15,20 @@ class FullScreenImage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return PhotoView( return Scaffold(
imageProvider: CachedNetworkImageProvider(url), appBar: AppBar(
maxScale: PhotoViewComputedScale.covered, backgroundColor: Colors.black,
minScale: PhotoViewComputedScale.contained, iconTheme: IconThemeData(
heroAttributes: PhotoViewHeroAttributes( color: Colors.white,
tag: url, ),
),
body: PhotoView(
imageProvider: CachedNetworkImageProvider(url),
maxScale: PhotoViewComputedScale.covered,
minScale: PhotoViewComputedScale.contained,
heroAttributes: PhotoViewHeroAttributes(
tag: url,
),
), ),
); );
} }
+6
View File
@@ -26,6 +26,12 @@ class _FullScreenVideoState extends State<FullScreenVideo> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
iconTheme: IconThemeData(
color: Colors.white,
),
),
body: Builder( body: Builder(
key: _scaffoldKey, key: _scaffoldKey,
builder: (context) { builder: (context) {
+7 -4
View File
@@ -182,7 +182,7 @@ class MessageInputState extends State<MessageInput> {
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Stack( child: Stack(
overflow: Overflow.visible, clipBehavior: Clip.none,
children: <Widget>[ children: <Widget>[
_buildBorder(context), _buildBorder(context),
Column( Column(
@@ -738,7 +738,10 @@ class MessageInputState extends State<MessageInput> {
} else if (fileType == DefaultAttachmentTypes.file) { } else if (fileType == DefaultAttachmentTypes.file) {
type = FileType.any; type = FileType.any;
} }
file = await FilePicker.getFile(type: type); final res = await FilePicker.platform.pickFiles(type: type);
if (res?.files?.isNotEmpty == true) {
file = File(res.files.first.path);
}
} }
setState(() { setState(() {
@@ -909,9 +912,9 @@ class MessageInputState extends State<MessageInput> {
); );
} }
return sendingFuture.whenComplete(() { return sendingFuture.then((resp) {
if (widget.onMessageSent != null) { if (widget.onMessageSent != null) {
widget.onMessageSent(message); widget.onMessageSent(resp.message);
} else { } else {
if (widget.editMessage != null) { if (widget.editMessage != null) {
Navigator.pop(context); Navigator.pop(context);
+5
View File
@@ -104,6 +104,7 @@ class MessageListView extends StatefulWidget {
this.onThreadTap, this.onThreadTap,
this.dateDividerBuilder, this.dateDividerBuilder,
this.scrollPhysics = const AlwaysScrollableScrollPhysics(), this.scrollPhysics = const AlwaysScrollableScrollPhysics(),
this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
}) : super(key: key); }) : super(key: key);
/// Function used to build a custom message widget /// Function used to build a custom message widget
@@ -128,6 +129,9 @@ class MessageListView extends StatefulWidget {
/// The ScrollPhysics used by the ListView /// The ScrollPhysics used by the ListView
final ScrollPhysics scrollPhysics; final ScrollPhysics scrollPhysics;
/// The [ScrollViewKeyboardDismissBehavior] used by the ListView
final ScrollViewKeyboardDismissBehavior keyboardDismissBehavior;
@override @override
_MessageListViewState createState() => _MessageListViewState(); _MessageListViewState createState() => _MessageListViewState();
} }
@@ -159,6 +163,7 @@ class _MessageListViewState extends State<MessageListView> {
child: ListView.custom( child: ListView.custom(
key: Key('messageListView'), key: Key('messageListView'),
physics: widget.scrollPhysics, physics: widget.scrollPhysics,
keyboardDismissBehavior: widget.keyboardDismissBehavior,
controller: _scrollController, controller: _scrollController,
reverse: true, reverse: true,
childrenDelegate: SliverChildBuilderDelegate( childrenDelegate: SliverChildBuilderDelegate(
+7 -1
View File
@@ -11,10 +11,12 @@ class MessageText extends StatelessWidget {
@required this.message, @required this.message,
@required this.messageTheme, @required this.messageTheme,
this.onMentionTap, this.onMentionTap,
this.onLinkTap,
}) : super(key: key); }) : super(key: key);
final Message message; final Message message;
final void Function(User) onMentionTap; final void Function(User) onMentionTap;
final void Function(String) onLinkTap;
final MessageTheme messageTheme; final MessageTheme messageTheme;
@override @override
@@ -35,7 +37,11 @@ class MessageText extends StatelessWidget {
print('tap on ${mentionedUser.name}'); print('tap on ${mentionedUser.name}');
} }
} else { } else {
launchURL(context, link); if (onLinkTap != null) {
onLinkTap(link);
} else {
launchURL(context, link);
}
} }
}, },
styleSheet: MarkdownStyleSheet.fromTheme( styleSheet: MarkdownStyleSheet.fromTheme(
+5
View File
@@ -101,6 +101,9 @@ class MessageWidget extends StatefulWidget {
/// The function called when tapping on UserAvatar /// The function called when tapping on UserAvatar
final void Function(User) onUserAvatarTap; final void Function(User) onUserAvatarTap;
/// The function called when tapping on a link
final void Function(String) onLinkTap;
final List<Read> readList; final List<Read> readList;
/// If true show the users username next to the timestamp of the message /// If true show the users username next to the timestamp of the message
@@ -132,6 +135,7 @@ class MessageWidget extends StatefulWidget {
this.showDeleteMessage = true, this.showDeleteMessage = true,
this.showEditMessage = true, this.showEditMessage = true,
this.onUserAvatarTap, this.onUserAvatarTap,
this.onLinkTap,
this.onMessageActions, this.onMessageActions,
this.editMessageInputBuilder, this.editMessageInputBuilder,
this.textBuilder, this.textBuilder,
@@ -814,6 +818,7 @@ class _MessageWidgetState extends State<MessageWidget> {
return widget.textBuilder != null return widget.textBuilder != null
? widget.textBuilder(context, widget.message) ? widget.textBuilder(context, widget.message)
: MessageText( : MessageText(
onLinkTap: widget.onLinkTap,
message: widget.message, message: widget.message,
onMentionTap: widget.onMentionTap, onMentionTap: widget.onMentionTap,
messageTheme: widget.messageTheme, messageTheme: widget.messageTheme,
+49 -46
View File
@@ -176,55 +176,58 @@ class StreamChatState extends State<StreamChat> with WidgetsBindingObserver {
@override @override
void didChangeAppLifecycleState(AppLifecycleState state) { void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.paused) { if (client.state?.user != null) {
if (client.showLocalNotification != null) { if (state == AppLifecycleState.paused) {
_newMessageSubscription = client if (client.showLocalNotification != null) {
.on(EventType.messageNew) _newMessageSubscription = client
.where((e) => e.user?.id != user.id) .on(EventType.messageNew)
.where((e) => e.message.silent != true) .where((e) => e.user?.id != user.id)
.listen((event) async { .where((e) => e.message.silent != true)
var channel = client.state.channels[event.cid]; .listen((event) async {
var channel = client.state.channels[event.cid];
if (channel == null) { if (channel == null) {
channel = client.channel( channel = client.channel(
event.type, event.type,
id: event.cid.split(':')[1], id: event.cid.split(':')[1],
);
await channel.query();
}
client.showLocalNotification(
event.message,
ChannelModel(
id: channel.id,
createdAt: channel.createdAt,
extraData: channel.extraData,
type: channel.type,
memberCount: channel.memberCount,
frozen: channel.frozen,
cid: channel.cid,
deletedAt: channel.deletedAt,
config: channel.config,
createdBy: channel.createdBy,
updatedAt: channel.updatedAt,
lastMessageAt: channel.lastMessageAt,
),
); );
await channel.query(); });
} _disconnectTimer = Timer(client.backgroundKeepAlive, () {
client.disconnect();
client.showLocalNotification( });
event.message, } else {
ChannelModel(
id: channel.id,
createdAt: channel.createdAt,
extraData: channel.extraData,
type: channel.type,
memberCount: channel.memberCount,
frozen: channel.frozen,
cid: channel.cid,
deletedAt: channel.deletedAt,
config: channel.config,
createdBy: channel.createdBy,
updatedAt: channel.updatedAt,
lastMessageAt: channel.lastMessageAt,
),
);
});
_disconnectTimer = Timer(client.backgroundKeepAlive, () {
client.disconnect(); client.disconnect();
}); }
} else { } else if (state == AppLifecycleState.resumed) {
client.disconnect(); _newMessageSubscription?.cancel();
} if (_disconnectTimer?.isActive == true) {
} else if (state == AppLifecycleState.resumed) { _disconnectTimer.cancel();
_newMessageSubscription?.cancel(); } else {
if (_disconnectTimer?.isActive == true) { if (client.wsConnectionStatus.value ==
_disconnectTimer.cancel(); ConnectionStatus.disconnected) {
} else { NotificationService.handleIosMessageQueue(client);
if (client.wsConnectionStatus.value == ConnectionStatus.disconnected) { client.connect();
NotificationService.handleIosMessageQueue(client); }
client.connect();
} }
} }
} }
+1 -1
View File
@@ -34,7 +34,7 @@ class TypingIndicator extends StatelessWidget {
builder: (context, snapshot) { builder: (context, snapshot) {
return AnimatedSwitcher( return AnimatedSwitcher(
duration: Duration(milliseconds: 300), duration: Duration(milliseconds: 300),
child: snapshot.data.isNotEmpty child: snapshot.data?.isNotEmpty == true
? Align( ? Align(
key: Key('typings'), key: Key('typings'),
alignment: alignment, alignment: alignment,
+6 -3
View File
@@ -1,7 +1,7 @@
name: stream_chat_flutter name: stream_chat_flutter
homepage: https://github.com/GetStream/stream-chat-flutter homepage: https://github.com/GetStream/stream-chat-flutter
description: Stream Chat official Flutter SDK. Build your own chat experience using Dart and Flutter. description: Stream Chat official Flutter SDK. Build your own chat experience using Dart and Flutter.
version: 0.2.4 version: 0.2.8+3
repository: https://github.com/GetStream/stream-chat-flutter repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
@@ -20,11 +20,11 @@ dependencies:
url_launcher: ^5.4.11 url_launcher: ^5.4.11
video_player: ^0.10.11+1 video_player: ^0.10.11+1
chewie: ^0.9.10 chewie: ^0.9.10
file_picker: ^1.12.0 file_picker: ^2.0.0
image_picker: ^0.6.7+2 image_picker: ^0.6.7+2
flutter_keyboard_visibility: ^3.2.1 flutter_keyboard_visibility: ^3.2.1
flutter_svg: ^0.18.0 flutter_svg: ^0.18.0
stream_chat: ^0.2.3+3 stream_chat: ^0.2.5+2
mime: ^0.9.6+3 mime: ^0.9.6+3
visibility_detector: ^0.1.5 visibility_detector: ^0.1.5
line_awesome_icons: ^1.0.4+2 line_awesome_icons: ^1.0.4+2
@@ -38,3 +38,6 @@ flutter:
dev_dependencies: dev_dependencies:
pedantic: ^1.9.0 pedantic: ^1.9.0
flutter_test:
sdk: flutter
mockito: ^4.1.1
+52
View File
@@ -0,0 +1,52 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
class MockClient extends Mock implements Client {}
class MockChannel extends Mock implements Channel {}
class MockChannelState extends Mock implements ChannelClientState {}
void main() {
testWidgets(
'it should show basic channel information',
(WidgetTester tester) async {
final client = MockClient();
final channel = MockChannel();
final channelState = MockChannelState();
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
when(channel.lastMessageAt).thenReturn(lastMessageAt);
when(channel.state).thenReturn(channelState);
when(channel.extraData).thenReturn({
'name': 'test name',
});
when(channelState.unreadCount).thenReturn(1);
when(channelState.lastMessage).thenReturn(Message(
text: 'hello',
));
await tester.pumpWidget(MaterialApp(
home: StreamChat(
client: client,
child: StreamChannel(
channel: channel,
child: Scaffold(
body: ChannelPreview(
channel: channel,
),
),
),
),
));
expect(find.text('22/06/2020'), findsOneWidget);
expect(find.text('test name'), findsOneWidget);
expect(find.text('1'), findsOneWidget);
expect(find.text('hello'), findsOneWidget);
expect(find.byType(ChannelImage), findsOneWidget);
},
);
}