Merge branch 'master' into feature/new-ui
This commit is contained in:
+21
-26
@@ -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
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
[](https://pub.dartlang.org/packages/stream_chat_flutter)
|
[](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)
|
[](https://gitter.im/GetStream/stream-chat-flutter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||||
|

|
||||||
|
[](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%" />
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,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"
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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
@@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user