├── LICENSE
├── README.md
├── api
└── proto
│ └── v1
│ └── chat.proto
├── flutter-grpc-tutorial.code-workspace
├── flutter_client
├── .gitignore
├── .metadata
├── README.md
├── android
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── flutterclient
│ │ │ │ └── MainActivity.java
│ │ │ └── res
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ └── settings.gradle
├── ios
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── Runner
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ │ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── main.m
├── lib
│ ├── api
│ │ ├── chat_service.dart
│ │ └── v1
│ │ │ ├── chat.pb.dart
│ │ │ ├── chat.pbenum.dart
│ │ │ ├── chat.pbgrpc.dart
│ │ │ ├── chat.pbjson.dart
│ │ │ └── google
│ │ │ └── protobuf
│ │ │ ├── empty.pb.dart
│ │ │ ├── empty.pbenum.dart
│ │ │ ├── empty.pbjson.dart
│ │ │ ├── timestamp.pb.dart
│ │ │ ├── timestamp.pbenum.dart
│ │ │ ├── timestamp.pbjson.dart
│ │ │ ├── wrappers.pb.dart
│ │ │ ├── wrappers.pbenum.dart
│ │ │ └── wrappers.pbjson.dart
│ ├── blocs
│ │ ├── application_bloc.dart
│ │ ├── bloc_provider.dart
│ │ └── message_events.dart
│ ├── main.dart
│ ├── models
│ │ ├── message.dart
│ │ ├── message_incoming.dart
│ │ └── message_outgoing.dart
│ ├── pages
│ │ └── home.dart
│ ├── theme.dart
│ └── widgets
│ │ ├── chat_message.dart
│ │ ├── chat_message_incoming.dart
│ │ └── chat_message_outgoing.dart
└── pubspec.yaml
├── go-server
├── .gitignore
├── .vscode
│ └── launch.json
├── cmd
│ └── server
│ │ └── main.go
├── go.mod
└── pkg
│ ├── api
│ └── v1
│ │ └── chat.pb.go
│ ├── protocol
│ └── grpc
│ │ └── server.go
│ └── service
│ └── v1
│ └── chat.go
└── third_party
├── google
└── protobuf
│ ├── empty.proto
│ ├── timestamp.proto
│ └── wrappers.proto
└── protoc-gen.cmd
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Source code for article [Asynchronous Flutter chat client with Go chat server which are powered by gRPC (simple and streaming)](https://medium.com/@amsokol.com/tutorial-asynchronous-flutter-chat-client-with-go-chat-server-which-are-powered-by-grpc-simple-ce913066861c)
2 |
--------------------------------------------------------------------------------
/api/proto/v1/chat.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package v1;
4 |
5 | import "google/protobuf/empty.proto";
6 | import "google/protobuf/wrappers.proto";
7 |
8 | // Message is response for ChatService.Subscribe method
9 | message Message{
10 | // message body
11 | string text = 1;
12 | }
13 |
14 | service ChatService {
15 | // Send sends message to the server
16 | rpc Send(google.protobuf.StringValue) returns (google.protobuf.Empty) {}
17 |
18 | // Subscribe is streaming method to get echo messages from the server
19 | rpc Subscribe(google.protobuf.Empty) returns (stream Message) {}
20 | }
21 |
--------------------------------------------------------------------------------
/flutter-grpc-tutorial.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "path": "api"
5 | },
6 | {
7 | "path": "flutter_client"
8 | },
9 | {
10 | "path": "go-server"
11 | },
12 | {
13 | "path": "third_party"
14 | }
15 | ],
16 | "settings": {
17 | "cSpell.words": [
18 | "Friendlychat",
19 | "Stateful",
20 | "amsokol",
21 | "cupertino",
22 | "grpc",
23 | "noname",
24 | "pbgrpc",
25 | "protobuf",
26 | "ptypes",
27 | "rxdart",
28 | "uuid",
29 | "vsync"
30 | ]
31 | }
32 | }
--------------------------------------------------------------------------------
/flutter_client/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.lock
4 | *.log
5 | *.pyc
6 | *.swp
7 | .DS_Store
8 | .atom/
9 | .buildlog/
10 | .history
11 | .svn/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # Visual Studio Code related
20 | .vscode/
21 |
22 | # Flutter/Dart/Pub related
23 | **/doc/api/
24 | .dart_tool/
25 | .flutter-plugins
26 | .packages
27 | .pub-cache/
28 | .pub/
29 | build/
30 |
31 | # Android related
32 | **/android/**/gradle-wrapper.jar
33 | **/android/.gradle
34 | **/android/captures/
35 | **/android/gradlew
36 | **/android/gradlew.bat
37 | **/android/local.properties
38 | **/android/**/GeneratedPluginRegistrant.java
39 |
40 | # iOS/XCode related
41 | **/ios/**/*.mode1v3
42 | **/ios/**/*.mode2v3
43 | **/ios/**/*.moved-aside
44 | **/ios/**/*.pbxuser
45 | **/ios/**/*.perspectivev3
46 | **/ios/**/*sync/
47 | **/ios/**/.sconsign.dblite
48 | **/ios/**/.tags*
49 | **/ios/**/.vagrant/
50 | **/ios/**/DerivedData/
51 | **/ios/**/Icon?
52 | **/ios/**/Pods/
53 | **/ios/**/.symlinks/
54 | **/ios/**/profile
55 | **/ios/**/xcuserdata
56 | **/ios/.generated/
57 | **/ios/Flutter/App.framework
58 | **/ios/Flutter/Flutter.framework
59 | **/ios/Flutter/Generated.xcconfig
60 | **/ios/Flutter/app.flx
61 | **/ios/Flutter/app.zip
62 | **/ios/Flutter/flutter_assets/
63 | **/ios/ServiceDefinitions.json
64 | **/ios/Runner/GeneratedPluginRegistrant.*
65 |
66 | # Exceptions to above rules.
67 | !**/ios/**/default.mode1v3
68 | !**/ios/**/default.mode2v3
69 | !**/ios/**/default.pbxuser
70 | !**/ios/**/default.perspectivev3
71 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
72 |
--------------------------------------------------------------------------------
/flutter_client/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 5391447fae6209bb21a89e6a5a6583cac1af9b4b
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/flutter_client/README.md:
--------------------------------------------------------------------------------
1 | # flutter_client
2 |
3 | A new Flutter project.
4 |
5 | ## Getting Started
6 |
7 | This project is a starting point for a Flutter application.
8 |
9 | A few resources to get you started if this is your first Flutter project:
10 |
11 | - [Lab: Write your first Flutter app](https://flutter.io/docs/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://flutter.io/docs/cookbook)
13 |
14 | For help getting started with Flutter, view our
15 | [online documentation](https://flutter.io/docs), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/flutter_client/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
26 |
27 | android {
28 | compileSdkVersion 27
29 |
30 | lintOptions {
31 | disable 'InvalidPackage'
32 | }
33 |
34 | defaultConfig {
35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
36 | applicationId "io.amsokol.flutterclient"
37 | minSdkVersion 16
38 | targetSdkVersion 27
39 | versionCode flutterVersionCode.toInteger()
40 | versionName flutterVersionName
41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
42 | }
43 |
44 | buildTypes {
45 | release {
46 | // TODO: Add your own signing config for the release build.
47 | // Signing with the debug keys for now, so `flutter run --release` works.
48 | signingConfig signingConfigs.debug
49 | }
50 | }
51 | }
52 |
53 | flutter {
54 | source '../..'
55 | }
56 |
57 | dependencies {
58 | testImplementation 'junit:junit:4.12'
59 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
61 | }
62 |
--------------------------------------------------------------------------------
/flutter_client/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
15 |
19 |
26 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/flutter_client/android/app/src/main/java/com/example/flutterclient/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.flutterclient;
2 |
3 | import android.os.Bundle;
4 | import io.flutter.app.FlutterActivity;
5 | import io.flutter.plugins.GeneratedPluginRegistrant;
6 |
7 | public class MainActivity extends FlutterActivity {
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | GeneratedPluginRegistrant.registerWith(this);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/flutter_client/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/flutter_client/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/flutter_client/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/flutter_client/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/flutter_client/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/flutter_client/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/flutter_client/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/flutter_client/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.2.1'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | rootProject.buildDir = '../build'
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/flutter_client/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 |
--------------------------------------------------------------------------------
/flutter_client/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
7 |
--------------------------------------------------------------------------------
/flutter_client/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/flutter_client/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/flutter_client/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/flutter_client/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/flutter_client/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
13 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
14 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
15 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
16 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
17 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
18 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
19 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
20 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
21 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
22 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
23 | /* End PBXBuildFile section */
24 |
25 | /* Begin PBXCopyFilesBuildPhase section */
26 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
27 | isa = PBXCopyFilesBuildPhase;
28 | buildActionMask = 2147483647;
29 | dstPath = "";
30 | dstSubfolderSpec = 10;
31 | files = (
32 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
33 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
34 | );
35 | name = "Embed Frameworks";
36 | runOnlyForDeploymentPostprocessing = 0;
37 | };
38 | /* End PBXCopyFilesBuildPhase section */
39 |
40 | /* Begin PBXFileReference section */
41 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
42 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
43 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
44 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
45 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; };
46 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
47 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
48 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
49 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
50 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
51 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; };
52 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
53 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
54 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
55 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
56 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
57 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
58 | /* End PBXFileReference section */
59 |
60 | /* Begin PBXFrameworksBuildPhase section */
61 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
62 | isa = PBXFrameworksBuildPhase;
63 | buildActionMask = 2147483647;
64 | files = (
65 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
66 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
67 | );
68 | runOnlyForDeploymentPostprocessing = 0;
69 | };
70 | /* End PBXFrameworksBuildPhase section */
71 |
72 | /* Begin PBXGroup section */
73 | 9740EEB11CF90186004384FC /* Flutter */ = {
74 | isa = PBXGroup;
75 | children = (
76 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
77 | 3B80C3931E831B6300D905FE /* App.framework */,
78 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
79 | 9740EEBA1CF902C7004384FC /* Flutter.framework */,
80 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
81 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
82 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
83 | );
84 | name = Flutter;
85 | sourceTree = "";
86 | };
87 | 97C146E51CF9000F007C117D = {
88 | isa = PBXGroup;
89 | children = (
90 | 9740EEB11CF90186004384FC /* Flutter */,
91 | 97C146F01CF9000F007C117D /* Runner */,
92 | 97C146EF1CF9000F007C117D /* Products */,
93 | CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
94 | );
95 | sourceTree = "";
96 | };
97 | 97C146EF1CF9000F007C117D /* Products */ = {
98 | isa = PBXGroup;
99 | children = (
100 | 97C146EE1CF9000F007C117D /* Runner.app */,
101 | );
102 | name = Products;
103 | sourceTree = "";
104 | };
105 | 97C146F01CF9000F007C117D /* Runner */ = {
106 | isa = PBXGroup;
107 | children = (
108 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
109 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
110 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
111 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
112 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
113 | 97C147021CF9000F007C117D /* Info.plist */,
114 | 97C146F11CF9000F007C117D /* Supporting Files */,
115 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
116 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
117 | );
118 | path = Runner;
119 | sourceTree = "";
120 | };
121 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
122 | isa = PBXGroup;
123 | children = (
124 | 97C146F21CF9000F007C117D /* main.m */,
125 | );
126 | name = "Supporting Files";
127 | sourceTree = "";
128 | };
129 | /* End PBXGroup section */
130 |
131 | /* Begin PBXNativeTarget section */
132 | 97C146ED1CF9000F007C117D /* Runner */ = {
133 | isa = PBXNativeTarget;
134 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
135 | buildPhases = (
136 | 9740EEB61CF901F6004384FC /* Run Script */,
137 | 97C146EA1CF9000F007C117D /* Sources */,
138 | 97C146EB1CF9000F007C117D /* Frameworks */,
139 | 97C146EC1CF9000F007C117D /* Resources */,
140 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
141 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
142 | );
143 | buildRules = (
144 | );
145 | dependencies = (
146 | );
147 | name = Runner;
148 | productName = Runner;
149 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
150 | productType = "com.apple.product-type.application";
151 | };
152 | /* End PBXNativeTarget section */
153 |
154 | /* Begin PBXProject section */
155 | 97C146E61CF9000F007C117D /* Project object */ = {
156 | isa = PBXProject;
157 | attributes = {
158 | LastUpgradeCheck = 0910;
159 | ORGANIZATIONNAME = "The Chromium Authors";
160 | TargetAttributes = {
161 | 97C146ED1CF9000F007C117D = {
162 | CreatedOnToolsVersion = 7.3.1;
163 | };
164 | };
165 | };
166 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
167 | compatibilityVersion = "Xcode 3.2";
168 | developmentRegion = English;
169 | hasScannedForEncodings = 0;
170 | knownRegions = (
171 | en,
172 | Base,
173 | );
174 | mainGroup = 97C146E51CF9000F007C117D;
175 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
176 | projectDirPath = "";
177 | projectRoot = "";
178 | targets = (
179 | 97C146ED1CF9000F007C117D /* Runner */,
180 | );
181 | };
182 | /* End PBXProject section */
183 |
184 | /* Begin PBXResourcesBuildPhase section */
185 | 97C146EC1CF9000F007C117D /* Resources */ = {
186 | isa = PBXResourcesBuildPhase;
187 | buildActionMask = 2147483647;
188 | files = (
189 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
190 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
191 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
192 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
193 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
194 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
195 | );
196 | runOnlyForDeploymentPostprocessing = 0;
197 | };
198 | /* End PBXResourcesBuildPhase section */
199 |
200 | /* Begin PBXShellScriptBuildPhase section */
201 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
202 | isa = PBXShellScriptBuildPhase;
203 | buildActionMask = 2147483647;
204 | files = (
205 | );
206 | inputPaths = (
207 | );
208 | name = "Thin Binary";
209 | outputPaths = (
210 | );
211 | runOnlyForDeploymentPostprocessing = 0;
212 | shellPath = /bin/sh;
213 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
214 | };
215 | 9740EEB61CF901F6004384FC /* Run Script */ = {
216 | isa = PBXShellScriptBuildPhase;
217 | buildActionMask = 2147483647;
218 | files = (
219 | );
220 | inputPaths = (
221 | );
222 | name = "Run Script";
223 | outputPaths = (
224 | );
225 | runOnlyForDeploymentPostprocessing = 0;
226 | shellPath = /bin/sh;
227 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
228 | };
229 | /* End PBXShellScriptBuildPhase section */
230 |
231 | /* Begin PBXSourcesBuildPhase section */
232 | 97C146EA1CF9000F007C117D /* Sources */ = {
233 | isa = PBXSourcesBuildPhase;
234 | buildActionMask = 2147483647;
235 | files = (
236 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
237 | 97C146F31CF9000F007C117D /* main.m in Sources */,
238 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
239 | );
240 | runOnlyForDeploymentPostprocessing = 0;
241 | };
242 | /* End PBXSourcesBuildPhase section */
243 |
244 | /* Begin PBXVariantGroup section */
245 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
246 | isa = PBXVariantGroup;
247 | children = (
248 | 97C146FB1CF9000F007C117D /* Base */,
249 | );
250 | name = Main.storyboard;
251 | sourceTree = "";
252 | };
253 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
254 | isa = PBXVariantGroup;
255 | children = (
256 | 97C147001CF9000F007C117D /* Base */,
257 | );
258 | name = LaunchScreen.storyboard;
259 | sourceTree = "";
260 | };
261 | /* End PBXVariantGroup section */
262 |
263 | /* Begin XCBuildConfiguration section */
264 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
265 | isa = XCBuildConfiguration;
266 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
267 | buildSettings = {
268 | ALWAYS_SEARCH_USER_PATHS = NO;
269 | CLANG_ANALYZER_NONNULL = YES;
270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
271 | CLANG_CXX_LIBRARY = "libc++";
272 | CLANG_ENABLE_MODULES = YES;
273 | CLANG_ENABLE_OBJC_ARC = YES;
274 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
275 | CLANG_WARN_BOOL_CONVERSION = YES;
276 | CLANG_WARN_COMMA = YES;
277 | CLANG_WARN_CONSTANT_CONVERSION = YES;
278 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
279 | CLANG_WARN_EMPTY_BODY = YES;
280 | CLANG_WARN_ENUM_CONVERSION = YES;
281 | CLANG_WARN_INFINITE_RECURSION = YES;
282 | CLANG_WARN_INT_CONVERSION = YES;
283 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
284 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
285 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
286 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
287 | CLANG_WARN_STRICT_PROTOTYPES = YES;
288 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
289 | CLANG_WARN_UNREACHABLE_CODE = YES;
290 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
291 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
292 | COPY_PHASE_STRIP = NO;
293 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
294 | ENABLE_NS_ASSERTIONS = NO;
295 | ENABLE_STRICT_OBJC_MSGSEND = YES;
296 | GCC_C_LANGUAGE_STANDARD = gnu99;
297 | GCC_NO_COMMON_BLOCKS = YES;
298 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
299 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
300 | GCC_WARN_UNDECLARED_SELECTOR = YES;
301 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
302 | GCC_WARN_UNUSED_FUNCTION = YES;
303 | GCC_WARN_UNUSED_VARIABLE = YES;
304 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
305 | MTL_ENABLE_DEBUG_INFO = NO;
306 | SDKROOT = iphoneos;
307 | TARGETED_DEVICE_FAMILY = "1,2";
308 | VALIDATE_PRODUCT = YES;
309 | };
310 | name = Profile;
311 | };
312 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
313 | isa = XCBuildConfiguration;
314 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
315 | buildSettings = {
316 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
317 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
318 | DEVELOPMENT_TEAM = S8QB4VV633;
319 | ENABLE_BITCODE = NO;
320 | FRAMEWORK_SEARCH_PATHS = (
321 | "$(inherited)",
322 | "$(PROJECT_DIR)/Flutter",
323 | );
324 | INFOPLIST_FILE = Runner/Info.plist;
325 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
326 | LIBRARY_SEARCH_PATHS = (
327 | "$(inherited)",
328 | "$(PROJECT_DIR)/Flutter",
329 | );
330 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterClient;
331 | PRODUCT_NAME = "$(TARGET_NAME)";
332 | VERSIONING_SYSTEM = "apple-generic";
333 | };
334 | name = Profile;
335 | };
336 | 97C147031CF9000F007C117D /* Debug */ = {
337 | isa = XCBuildConfiguration;
338 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
339 | buildSettings = {
340 | ALWAYS_SEARCH_USER_PATHS = NO;
341 | CLANG_ANALYZER_NONNULL = YES;
342 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
343 | CLANG_CXX_LIBRARY = "libc++";
344 | CLANG_ENABLE_MODULES = YES;
345 | CLANG_ENABLE_OBJC_ARC = YES;
346 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
347 | CLANG_WARN_BOOL_CONVERSION = YES;
348 | CLANG_WARN_COMMA = YES;
349 | CLANG_WARN_CONSTANT_CONVERSION = YES;
350 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
351 | CLANG_WARN_EMPTY_BODY = YES;
352 | CLANG_WARN_ENUM_CONVERSION = YES;
353 | CLANG_WARN_INFINITE_RECURSION = YES;
354 | CLANG_WARN_INT_CONVERSION = YES;
355 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
356 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
357 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
358 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
359 | CLANG_WARN_STRICT_PROTOTYPES = YES;
360 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
361 | CLANG_WARN_UNREACHABLE_CODE = YES;
362 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
363 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
364 | COPY_PHASE_STRIP = NO;
365 | DEBUG_INFORMATION_FORMAT = dwarf;
366 | ENABLE_STRICT_OBJC_MSGSEND = YES;
367 | ENABLE_TESTABILITY = YES;
368 | GCC_C_LANGUAGE_STANDARD = gnu99;
369 | GCC_DYNAMIC_NO_PIC = NO;
370 | GCC_NO_COMMON_BLOCKS = YES;
371 | GCC_OPTIMIZATION_LEVEL = 0;
372 | GCC_PREPROCESSOR_DEFINITIONS = (
373 | "DEBUG=1",
374 | "$(inherited)",
375 | );
376 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
377 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
378 | GCC_WARN_UNDECLARED_SELECTOR = YES;
379 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
380 | GCC_WARN_UNUSED_FUNCTION = YES;
381 | GCC_WARN_UNUSED_VARIABLE = YES;
382 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
383 | MTL_ENABLE_DEBUG_INFO = YES;
384 | ONLY_ACTIVE_ARCH = YES;
385 | SDKROOT = iphoneos;
386 | TARGETED_DEVICE_FAMILY = "1,2";
387 | };
388 | name = Debug;
389 | };
390 | 97C147041CF9000F007C117D /* Release */ = {
391 | isa = XCBuildConfiguration;
392 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
393 | buildSettings = {
394 | ALWAYS_SEARCH_USER_PATHS = NO;
395 | CLANG_ANALYZER_NONNULL = YES;
396 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
397 | CLANG_CXX_LIBRARY = "libc++";
398 | CLANG_ENABLE_MODULES = YES;
399 | CLANG_ENABLE_OBJC_ARC = YES;
400 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
401 | CLANG_WARN_BOOL_CONVERSION = YES;
402 | CLANG_WARN_COMMA = YES;
403 | CLANG_WARN_CONSTANT_CONVERSION = YES;
404 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
405 | CLANG_WARN_EMPTY_BODY = YES;
406 | CLANG_WARN_ENUM_CONVERSION = YES;
407 | CLANG_WARN_INFINITE_RECURSION = YES;
408 | CLANG_WARN_INT_CONVERSION = YES;
409 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
410 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
411 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
412 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
413 | CLANG_WARN_STRICT_PROTOTYPES = YES;
414 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
415 | CLANG_WARN_UNREACHABLE_CODE = YES;
416 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
417 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
418 | COPY_PHASE_STRIP = NO;
419 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
420 | ENABLE_NS_ASSERTIONS = NO;
421 | ENABLE_STRICT_OBJC_MSGSEND = YES;
422 | GCC_C_LANGUAGE_STANDARD = gnu99;
423 | GCC_NO_COMMON_BLOCKS = YES;
424 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
425 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
426 | GCC_WARN_UNDECLARED_SELECTOR = YES;
427 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
428 | GCC_WARN_UNUSED_FUNCTION = YES;
429 | GCC_WARN_UNUSED_VARIABLE = YES;
430 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
431 | MTL_ENABLE_DEBUG_INFO = NO;
432 | SDKROOT = iphoneos;
433 | TARGETED_DEVICE_FAMILY = "1,2";
434 | VALIDATE_PRODUCT = YES;
435 | };
436 | name = Release;
437 | };
438 | 97C147061CF9000F007C117D /* Debug */ = {
439 | isa = XCBuildConfiguration;
440 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
441 | buildSettings = {
442 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
443 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
444 | ENABLE_BITCODE = NO;
445 | FRAMEWORK_SEARCH_PATHS = (
446 | "$(inherited)",
447 | "$(PROJECT_DIR)/Flutter",
448 | );
449 | INFOPLIST_FILE = Runner/Info.plist;
450 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
451 | LIBRARY_SEARCH_PATHS = (
452 | "$(inherited)",
453 | "$(PROJECT_DIR)/Flutter",
454 | );
455 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterClient;
456 | PRODUCT_NAME = "$(TARGET_NAME)";
457 | VERSIONING_SYSTEM = "apple-generic";
458 | };
459 | name = Debug;
460 | };
461 | 97C147071CF9000F007C117D /* Release */ = {
462 | isa = XCBuildConfiguration;
463 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
464 | buildSettings = {
465 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
466 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
467 | ENABLE_BITCODE = NO;
468 | FRAMEWORK_SEARCH_PATHS = (
469 | "$(inherited)",
470 | "$(PROJECT_DIR)/Flutter",
471 | );
472 | INFOPLIST_FILE = Runner/Info.plist;
473 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
474 | LIBRARY_SEARCH_PATHS = (
475 | "$(inherited)",
476 | "$(PROJECT_DIR)/Flutter",
477 | );
478 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterClient;
479 | PRODUCT_NAME = "$(TARGET_NAME)";
480 | VERSIONING_SYSTEM = "apple-generic";
481 | };
482 | name = Release;
483 | };
484 | /* End XCBuildConfiguration section */
485 |
486 | /* Begin XCConfigurationList section */
487 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
488 | isa = XCConfigurationList;
489 | buildConfigurations = (
490 | 97C147031CF9000F007C117D /* Debug */,
491 | 97C147041CF9000F007C117D /* Release */,
492 | 249021D3217E4FDB00AE95B9 /* Profile */,
493 | );
494 | defaultConfigurationIsVisible = 0;
495 | defaultConfigurationName = Release;
496 | };
497 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
498 | isa = XCConfigurationList;
499 | buildConfigurations = (
500 | 97C147061CF9000F007C117D /* Debug */,
501 | 97C147071CF9000F007C117D /* Release */,
502 | 249021D4217E4FDB00AE95B9 /* Profile */,
503 | );
504 | defaultConfigurationIsVisible = 0;
505 | defaultConfigurationName = Release;
506 | };
507 | /* End XCConfigurationList section */
508 | };
509 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
510 | }
511 |
--------------------------------------------------------------------------------
/flutter_client/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/flutter_client/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
56 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
75 |
77 |
83 |
84 |
85 |
86 |
88 |
89 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/flutter_client/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #include "AppDelegate.h"
2 | #include "GeneratedPluginRegistrant.h"
3 |
4 | @implementation AppDelegate
5 |
6 | - (BOOL)application:(UIApplication *)application
7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
8 | [GeneratedPluginRegistrant registerWithRegistry:self];
9 | // Override point for customization after application launch.
10 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
11 | }
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amsokol/flutter-grpc-tutorial/d51eb682daa9528a7026f95b7c5891b3a7a08ec3/flutter_client/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | flutter_client
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/flutter_client/ios/Runner/main.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char* argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/flutter_client/lib/api/chat_service.dart:
--------------------------------------------------------------------------------
1 | import 'dart:isolate';
2 | import 'dart:io';
3 | import 'package:grpc/grpc.dart';
4 |
5 | import 'package:flutter_client/blocs/message_events.dart';
6 | import 'package:flutter_client/models/message_outgoing.dart';
7 |
8 | import 'v1/chat.pbgrpc.dart' as grpc;
9 | import 'v1/google/protobuf/empty.pb.dart';
10 | import 'v1/google/protobuf/wrappers.pb.dart';
11 |
12 | /// CHANGE TO IP ADDRESS OF YOUR SERVER IF IT IS NECESSARY
13 | const serverIP = "172.16.1.18";
14 | const serverPort = 3000;
15 |
16 | /// ChatService client implementation
17 | class ChatService {
18 | // _isolateSending is isolate to send chat messages
19 | Isolate _isolateSending;
20 |
21 | // Port to send message
22 | SendPort _portSending;
23 |
24 | // Port to get status of message sending
25 | ReceivePort _portSendStatus;
26 |
27 | // _isolateReceiving is isolate to receive chat messages
28 | Isolate _isolateReceiving;
29 |
30 | // Port to receive messages
31 | ReceivePort _portReceiving;
32 |
33 | /// Event is raised when message has been sent to the server successfully
34 | final void Function(MessageSentEvent event) onMessageSent;
35 |
36 | /// Event is raised when message sending is failed
37 | final void Function(MessageSendFailedEvent event) onMessageSendFailed;
38 |
39 | /// Event is raised when message has been received from the server
40 | final void Function(MessageReceivedEvent event) onMessageReceived;
41 |
42 | /// Event is raised when message receiving is failed
43 | final void Function(MessageReceiveFailedEvent event) onMessageReceiveFailed;
44 |
45 | /// Constructor
46 | ChatService(
47 | {this.onMessageSent,
48 | this.onMessageSendFailed,
49 | this.onMessageReceived,
50 | this.onMessageReceiveFailed})
51 | : _portSendStatus = ReceivePort(),
52 | _portReceiving = ReceivePort();
53 |
54 | // Start threads to send and receive messages
55 | void start() {
56 | _startSending();
57 | _startReceiving();
58 | }
59 |
60 | /// Start thread to send messages
61 | void _startSending() async {
62 | // start thread to send messages
63 | _isolateSending =
64 | await Isolate.spawn(_sendingIsolate, _portSendStatus.sendPort);
65 |
66 | // listen send status
67 | await for (var event in _portSendStatus) {
68 | if (event is SendPort) {
69 | _portSending = event;
70 | } else if (event is MessageSentEvent) {
71 | // call for success handler
72 | if (onMessageSent != null) {
73 | onMessageSent(event);
74 | }
75 | } else if (event is MessageSendFailedEvent) {
76 | // call for error handler
77 | if (onMessageSendFailed != null) {
78 | onMessageSendFailed(event);
79 | }
80 | } else {
81 | assert(false, 'Unknown event type ${event.runtimeType}');
82 | }
83 | }
84 | }
85 |
86 | /// Thread to send messages
87 | static void _sendingIsolate(SendPort portSendStatus) async {
88 | // Port to get messages to send
89 | ReceivePort portSendMessages = ReceivePort();
90 |
91 | // send port to send messages to the caller
92 | portSendStatus.send(portSendMessages.sendPort);
93 |
94 | ClientChannel client;
95 |
96 | // waiting messages to send
97 | await for (MessageOutgoing message in portSendMessages) {
98 | var sent = false;
99 | do {
100 | // create new client
101 | client ??= ClientChannel(
102 | serverIP, // Your IP here or localhost
103 | port: serverPort,
104 | options: ChannelOptions(
105 | //TODO: Change to secure with server certificates
106 | credentials: ChannelCredentials.insecure(),
107 | idleTimeout: Duration(seconds: 1),
108 | ),
109 | );
110 |
111 | try {
112 | // try to send
113 | var request = StringValue.create();
114 | request.value = message.text;
115 | await grpc.ChatServiceClient(client).send(request);
116 | // sent successfully
117 | portSendStatus.send(MessageSentEvent(id: message.id));
118 | sent = true;
119 | } catch (e) {
120 | // sent failed
121 | portSendStatus.send(
122 | MessageSendFailedEvent(id: message.id, error: e.toString()));
123 | // reset client
124 | client.shutdown();
125 | client = null;
126 | }
127 |
128 | if (!sent) {
129 | // try to send again
130 | sleep(Duration(seconds: 5));
131 | }
132 | } while (!sent);
133 | }
134 | }
135 |
136 | /// Start listening messages from the server
137 | void _startReceiving() async {
138 | // start thread to receive messages
139 | _isolateReceiving =
140 | await Isolate.spawn(_receivingIsolate, _portReceiving.sendPort);
141 |
142 | // listen for incoming messages
143 | await for (var event in _portReceiving) {
144 | if (event is MessageReceivedEvent) {
145 | if (onMessageReceived != null) {
146 | onMessageReceived(event);
147 | }
148 | } else if (event is MessageReceiveFailedEvent) {
149 | if (onMessageReceiveFailed != null) {
150 | onMessageReceiveFailed(event);
151 | }
152 | }
153 | }
154 | }
155 |
156 | /// Thread to listen messages from the server
157 | static void _receivingIsolate(SendPort portReceive) async {
158 | ClientChannel client;
159 |
160 | do {
161 | // create new client
162 | client ??= ClientChannel(
163 | serverIP, // Your IP here or localhost
164 | port: serverPort,
165 | options: ChannelOptions(
166 | //TODO: Change to secure with server certificates
167 | credentials: ChannelCredentials.insecure(),
168 | idleTimeout: Duration(seconds: 1),
169 | ),
170 | );
171 |
172 | var stream = grpc.ChatServiceClient(client).subscribe(Empty.create());
173 |
174 | try {
175 | await for (var message in stream) {
176 | portReceive.send(MessageReceivedEvent(text: message.text));
177 | }
178 | } catch (e) {
179 | // notify caller
180 | portReceive.send(MessageReceiveFailedEvent(error: e.toString()));
181 | // reset client
182 | client.shutdown();
183 | client = null;
184 | }
185 | // try to connect again
186 | sleep(Duration(seconds: 5));
187 | } while (true);
188 | }
189 |
190 | // Shutdown client
191 | void shutdown() {
192 | // stop sending
193 | _isolateSending?.kill(priority: Isolate.immediate);
194 | _isolateSending = null;
195 | _portSendStatus?.close();
196 | _portSendStatus = null;
197 |
198 | // stop receiving
199 | _isolateReceiving?.kill(priority: Isolate.immediate);
200 | _isolateReceiving = null;
201 | _portReceiving?.close();
202 | _portReceiving = null;
203 | }
204 |
205 | /// Send message to the server
206 | void send(MessageOutgoing message) {
207 | assert(_portSending != null, "Port to send message can't be null");
208 | _portSending.send(message);
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/flutter_client/lib/api/v1/chat.pb.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: chat.proto
4 | ///
5 | // ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
6 |
7 | // ignore: UNUSED_SHOWN_NAME
8 | import 'dart:core' show int, bool, double, String, List, Map, override;
9 |
10 | import 'package:protobuf/protobuf.dart' as $pb;
11 |
12 | class Message extends $pb.GeneratedMessage {
13 | static final $pb.BuilderInfo _i = new $pb.BuilderInfo('Message', package: const $pb.PackageName('v1'))
14 | ..aOS(1, 'text')
15 | ..hasRequiredFields = false
16 | ;
17 |
18 | Message() : super();
19 | Message.fromBuffer(List i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
20 | Message.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
21 | Message clone() => new Message()..mergeFromMessage(this);
22 | Message copyWith(void Function(Message) updates) => super.copyWith((message) => updates(message as Message));
23 | $pb.BuilderInfo get info_ => _i;
24 | static Message create() => new Message();
25 | Message createEmptyInstance() => create();
26 | static $pb.PbList createRepeated() => new $pb.PbList();
27 | static Message getDefault() => _defaultInstance ??= create()..freeze();
28 | static Message _defaultInstance;
29 | static void $checkItem(Message v) {
30 | if (v is! Message) $pb.checkItemFailed(v, _i.qualifiedMessageName);
31 | }
32 |
33 | String get text => $_getS(0, '');
34 | set text(String v) { $_setString(0, v); }
35 | bool hasText() => $_has(0);
36 | void clearText() => clearField(1);
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/flutter_client/lib/api/v1/chat.pbenum.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: chat.proto
4 | ///
5 | // ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
6 |
7 |
--------------------------------------------------------------------------------
/flutter_client/lib/api/v1/chat.pbgrpc.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: chat.proto
4 | ///
5 | // ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
6 |
7 | import 'dart:async' as $async;
8 |
9 | import 'package:grpc/grpc.dart';
10 |
11 | import 'google/protobuf/wrappers.pb.dart' as $0;
12 | import 'google/protobuf/empty.pb.dart' as $1;
13 | import 'chat.pb.dart';
14 | export 'chat.pb.dart';
15 |
16 | class ChatServiceClient extends Client {
17 | static final _$send = new ClientMethod<$0.StringValue, $1.Empty>(
18 | '/v1.ChatService/Send',
19 | ($0.StringValue value) => value.writeToBuffer(),
20 | (List value) => new $1.Empty.fromBuffer(value));
21 | static final _$subscribe = new ClientMethod<$1.Empty, Message>(
22 | '/v1.ChatService/Subscribe',
23 | ($1.Empty value) => value.writeToBuffer(),
24 | (List value) => new Message.fromBuffer(value));
25 |
26 | ChatServiceClient(ClientChannel channel, {CallOptions options})
27 | : super(channel, options: options);
28 |
29 | ResponseFuture<$1.Empty> send($0.StringValue request, {CallOptions options}) {
30 | final call = $createCall(_$send, new $async.Stream.fromIterable([request]),
31 | options: options);
32 | return new ResponseFuture(call);
33 | }
34 |
35 | ResponseStream subscribe($1.Empty request, {CallOptions options}) {
36 | final call = $createCall(
37 | _$subscribe, new $async.Stream.fromIterable([request]),
38 | options: options);
39 | return new ResponseStream(call);
40 | }
41 | }
42 |
43 | abstract class ChatServiceBase extends Service {
44 | String get $name => 'v1.ChatService';
45 |
46 | ChatServiceBase() {
47 | $addMethod(new ServiceMethod<$0.StringValue, $1.Empty>(
48 | 'Send',
49 | send_Pre,
50 | false,
51 | false,
52 | (List value) => new $0.StringValue.fromBuffer(value),
53 | ($1.Empty value) => value.writeToBuffer()));
54 | $addMethod(new ServiceMethod<$1.Empty, Message>(
55 | 'Subscribe',
56 | subscribe_Pre,
57 | false,
58 | true,
59 | (List value) => new $1.Empty.fromBuffer(value),
60 | (Message value) => value.writeToBuffer()));
61 | }
62 |
63 | $async.Future<$1.Empty> send_Pre(
64 | ServiceCall call, $async.Future request) async {
65 | return send(call, await request);
66 | }
67 |
68 | $async.Stream subscribe_Pre(
69 | ServiceCall call, $async.Future request) async* {
70 | yield* subscribe(call, (await request) as $1.Empty);
71 | }
72 |
73 | $async.Future<$1.Empty> send(ServiceCall call, $0.StringValue request);
74 | $async.Stream subscribe(ServiceCall call, $1.Empty request);
75 | }
76 |
--------------------------------------------------------------------------------
/flutter_client/lib/api/v1/chat.pbjson.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: chat.proto
4 | ///
5 | // ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
6 |
7 | const Message$json = const {
8 | '1': 'Message',
9 | '2': const [
10 | const {'1': 'text', '3': 1, '4': 1, '5': 9, '10': 'text'},
11 | ],
12 | };
13 |
14 |
--------------------------------------------------------------------------------
/flutter_client/lib/api/v1/google/protobuf/empty.pb.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: empty.proto
4 | ///
5 | // ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
6 |
7 | // ignore: UNUSED_SHOWN_NAME
8 | import 'dart:core' show int, bool, double, String, List, Map, override;
9 |
10 | import 'package:protobuf/protobuf.dart' as $pb;
11 |
12 | class Empty extends $pb.GeneratedMessage {
13 | static final $pb.BuilderInfo _i = new $pb.BuilderInfo('Empty', package: const $pb.PackageName('google.protobuf'))
14 | ..hasRequiredFields = false
15 | ;
16 |
17 | Empty() : super();
18 | Empty.fromBuffer(List i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
19 | Empty.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
20 | Empty clone() => new Empty()..mergeFromMessage(this);
21 | Empty copyWith(void Function(Empty) updates) => super.copyWith((message) => updates(message as Empty));
22 | $pb.BuilderInfo get info_ => _i;
23 | static Empty create() => new Empty();
24 | Empty createEmptyInstance() => create();
25 | static $pb.PbList createRepeated() => new $pb.PbList();
26 | static Empty getDefault() => _defaultInstance ??= create()..freeze();
27 | static Empty _defaultInstance;
28 | static void $checkItem(Empty v) {
29 | if (v is! Empty) $pb.checkItemFailed(v, _i.qualifiedMessageName);
30 | }
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/flutter_client/lib/api/v1/google/protobuf/empty.pbenum.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: empty.proto
4 | ///
5 | // ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
6 |
7 |
--------------------------------------------------------------------------------
/flutter_client/lib/api/v1/google/protobuf/empty.pbjson.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: empty.proto
4 | ///
5 | // ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
6 |
7 | const Empty$json = const {
8 | '1': 'Empty',
9 | };
10 |
11 |
--------------------------------------------------------------------------------
/flutter_client/lib/api/v1/google/protobuf/timestamp.pb.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: timestamp.proto
4 | ///
5 | // ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
6 |
7 | // ignore: UNUSED_SHOWN_NAME
8 | import 'dart:core' show int, bool, double, String, List, Map, override;
9 |
10 | import 'package:fixnum/fixnum.dart';
11 | import 'package:protobuf/protobuf.dart' as $pb;
12 |
13 | class Timestamp extends $pb.GeneratedMessage {
14 | static final $pb.BuilderInfo _i = new $pb.BuilderInfo('Timestamp', package: const $pb.PackageName('google.protobuf'))
15 | ..aInt64(1, 'seconds')
16 | ..a(2, 'nanos', $pb.PbFieldType.O3)
17 | ..hasRequiredFields = false
18 | ;
19 |
20 | Timestamp() : super();
21 | Timestamp.fromBuffer(List i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
22 | Timestamp.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
23 | Timestamp clone() => new Timestamp()..mergeFromMessage(this);
24 | Timestamp copyWith(void Function(Timestamp) updates) => super.copyWith((message) => updates(message as Timestamp));
25 | $pb.BuilderInfo get info_ => _i;
26 | static Timestamp create() => new Timestamp();
27 | Timestamp createEmptyInstance() => create();
28 | static $pb.PbList createRepeated() => new $pb.PbList();
29 | static Timestamp getDefault() => _defaultInstance ??= create()..freeze();
30 | static Timestamp _defaultInstance;
31 | static void $checkItem(Timestamp v) {
32 | if (v is! Timestamp) $pb.checkItemFailed(v, _i.qualifiedMessageName);
33 | }
34 |
35 | Int64 get seconds => $_getI64(0);
36 | set seconds(Int64 v) { $_setInt64(0, v); }
37 | bool hasSeconds() => $_has(0);
38 | void clearSeconds() => clearField(1);
39 |
40 | int get nanos => $_get(1, 0);
41 | set nanos(int v) { $_setSignedInt32(1, v); }
42 | bool hasNanos() => $_has(1);
43 | void clearNanos() => clearField(2);
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/flutter_client/lib/api/v1/google/protobuf/timestamp.pbenum.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: timestamp.proto
4 | ///
5 | // ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
6 |
7 |
--------------------------------------------------------------------------------
/flutter_client/lib/api/v1/google/protobuf/timestamp.pbjson.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: timestamp.proto
4 | ///
5 | // ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
6 |
7 | const Timestamp$json = const {
8 | '1': 'Timestamp',
9 | '2': const [
10 | const {'1': 'seconds', '3': 1, '4': 1, '5': 3, '10': 'seconds'},
11 | const {'1': 'nanos', '3': 2, '4': 1, '5': 5, '10': 'nanos'},
12 | ],
13 | };
14 |
15 |
--------------------------------------------------------------------------------
/flutter_client/lib/api/v1/google/protobuf/wrappers.pb.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: wrappers.proto
4 | ///
5 | // ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
6 |
7 | // ignore: UNUSED_SHOWN_NAME
8 | import 'dart:core' show int, bool, double, String, List, Map, override;
9 |
10 | import 'package:fixnum/fixnum.dart';
11 | import 'package:protobuf/protobuf.dart' as $pb;
12 |
13 | class DoubleValue extends $pb.GeneratedMessage {
14 | static final $pb.BuilderInfo _i = new $pb.BuilderInfo('DoubleValue', package: const $pb.PackageName('google.protobuf'))
15 | ..a(1, 'value', $pb.PbFieldType.OD)
16 | ..hasRequiredFields = false
17 | ;
18 |
19 | DoubleValue() : super();
20 | DoubleValue.fromBuffer(List i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
21 | DoubleValue.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
22 | DoubleValue clone() => new DoubleValue()..mergeFromMessage(this);
23 | DoubleValue copyWith(void Function(DoubleValue) updates) => super.copyWith((message) => updates(message as DoubleValue));
24 | $pb.BuilderInfo get info_ => _i;
25 | static DoubleValue create() => new DoubleValue();
26 | DoubleValue createEmptyInstance() => create();
27 | static $pb.PbList createRepeated() => new $pb.PbList();
28 | static DoubleValue getDefault() => _defaultInstance ??= create()..freeze();
29 | static DoubleValue _defaultInstance;
30 | static void $checkItem(DoubleValue v) {
31 | if (v is! DoubleValue) $pb.checkItemFailed(v, _i.qualifiedMessageName);
32 | }
33 |
34 | double get value => $_getN(0);
35 | set value(double v) { $_setDouble(0, v); }
36 | bool hasValue() => $_has(0);
37 | void clearValue() => clearField(1);
38 | }
39 |
40 | class FloatValue extends $pb.GeneratedMessage {
41 | static final $pb.BuilderInfo _i = new $pb.BuilderInfo('FloatValue', package: const $pb.PackageName('google.protobuf'))
42 | ..a(1, 'value', $pb.PbFieldType.OF)
43 | ..hasRequiredFields = false
44 | ;
45 |
46 | FloatValue() : super();
47 | FloatValue.fromBuffer(List i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
48 | FloatValue.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
49 | FloatValue clone() => new FloatValue()..mergeFromMessage(this);
50 | FloatValue copyWith(void Function(FloatValue) updates) => super.copyWith((message) => updates(message as FloatValue));
51 | $pb.BuilderInfo get info_ => _i;
52 | static FloatValue create() => new FloatValue();
53 | FloatValue createEmptyInstance() => create();
54 | static $pb.PbList createRepeated() => new $pb.PbList();
55 | static FloatValue getDefault() => _defaultInstance ??= create()..freeze();
56 | static FloatValue _defaultInstance;
57 | static void $checkItem(FloatValue v) {
58 | if (v is! FloatValue) $pb.checkItemFailed(v, _i.qualifiedMessageName);
59 | }
60 |
61 | double get value => $_getN(0);
62 | set value(double v) { $_setFloat(0, v); }
63 | bool hasValue() => $_has(0);
64 | void clearValue() => clearField(1);
65 | }
66 |
67 | class Int64Value extends $pb.GeneratedMessage {
68 | static final $pb.BuilderInfo _i = new $pb.BuilderInfo('Int64Value', package: const $pb.PackageName('google.protobuf'))
69 | ..aInt64(1, 'value')
70 | ..hasRequiredFields = false
71 | ;
72 |
73 | Int64Value() : super();
74 | Int64Value.fromBuffer(List i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
75 | Int64Value.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
76 | Int64Value clone() => new Int64Value()..mergeFromMessage(this);
77 | Int64Value copyWith(void Function(Int64Value) updates) => super.copyWith((message) => updates(message as Int64Value));
78 | $pb.BuilderInfo get info_ => _i;
79 | static Int64Value create() => new Int64Value();
80 | Int64Value createEmptyInstance() => create();
81 | static $pb.PbList createRepeated() => new $pb.PbList();
82 | static Int64Value getDefault() => _defaultInstance ??= create()..freeze();
83 | static Int64Value _defaultInstance;
84 | static void $checkItem(Int64Value v) {
85 | if (v is! Int64Value) $pb.checkItemFailed(v, _i.qualifiedMessageName);
86 | }
87 |
88 | Int64 get value => $_getI64(0);
89 | set value(Int64 v) { $_setInt64(0, v); }
90 | bool hasValue() => $_has(0);
91 | void clearValue() => clearField(1);
92 | }
93 |
94 | class UInt64Value extends $pb.GeneratedMessage {
95 | static final $pb.BuilderInfo _i = new $pb.BuilderInfo('UInt64Value', package: const $pb.PackageName('google.protobuf'))
96 | ..a(1, 'value', $pb.PbFieldType.OU6, Int64.ZERO)
97 | ..hasRequiredFields = false
98 | ;
99 |
100 | UInt64Value() : super();
101 | UInt64Value.fromBuffer(List i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
102 | UInt64Value.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
103 | UInt64Value clone() => new UInt64Value()..mergeFromMessage(this);
104 | UInt64Value copyWith(void Function(UInt64Value) updates) => super.copyWith((message) => updates(message as UInt64Value));
105 | $pb.BuilderInfo get info_ => _i;
106 | static UInt64Value create() => new UInt64Value();
107 | UInt64Value createEmptyInstance() => create();
108 | static $pb.PbList createRepeated() => new $pb.PbList();
109 | static UInt64Value getDefault() => _defaultInstance ??= create()..freeze();
110 | static UInt64Value _defaultInstance;
111 | static void $checkItem(UInt64Value v) {
112 | if (v is! UInt64Value) $pb.checkItemFailed(v, _i.qualifiedMessageName);
113 | }
114 |
115 | Int64 get value => $_getI64(0);
116 | set value(Int64 v) { $_setInt64(0, v); }
117 | bool hasValue() => $_has(0);
118 | void clearValue() => clearField(1);
119 | }
120 |
121 | class Int32Value extends $pb.GeneratedMessage {
122 | static final $pb.BuilderInfo _i = new $pb.BuilderInfo('Int32Value', package: const $pb.PackageName('google.protobuf'))
123 | ..a(1, 'value', $pb.PbFieldType.O3)
124 | ..hasRequiredFields = false
125 | ;
126 |
127 | Int32Value() : super();
128 | Int32Value.fromBuffer(List i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
129 | Int32Value.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
130 | Int32Value clone() => new Int32Value()..mergeFromMessage(this);
131 | Int32Value copyWith(void Function(Int32Value) updates) => super.copyWith((message) => updates(message as Int32Value));
132 | $pb.BuilderInfo get info_ => _i;
133 | static Int32Value create() => new Int32Value();
134 | Int32Value createEmptyInstance() => create();
135 | static $pb.PbList createRepeated() => new $pb.PbList();
136 | static Int32Value getDefault() => _defaultInstance ??= create()..freeze();
137 | static Int32Value _defaultInstance;
138 | static void $checkItem(Int32Value v) {
139 | if (v is! Int32Value) $pb.checkItemFailed(v, _i.qualifiedMessageName);
140 | }
141 |
142 | int get value => $_get(0, 0);
143 | set value(int v) { $_setSignedInt32(0, v); }
144 | bool hasValue() => $_has(0);
145 | void clearValue() => clearField(1);
146 | }
147 |
148 | class UInt32Value extends $pb.GeneratedMessage {
149 | static final $pb.BuilderInfo _i = new $pb.BuilderInfo('UInt32Value', package: const $pb.PackageName('google.protobuf'))
150 | ..a(1, 'value', $pb.PbFieldType.OU3)
151 | ..hasRequiredFields = false
152 | ;
153 |
154 | UInt32Value() : super();
155 | UInt32Value.fromBuffer(List i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
156 | UInt32Value.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
157 | UInt32Value clone() => new UInt32Value()..mergeFromMessage(this);
158 | UInt32Value copyWith(void Function(UInt32Value) updates) => super.copyWith((message) => updates(message as UInt32Value));
159 | $pb.BuilderInfo get info_ => _i;
160 | static UInt32Value create() => new UInt32Value();
161 | UInt32Value createEmptyInstance() => create();
162 | static $pb.PbList createRepeated() => new $pb.PbList();
163 | static UInt32Value getDefault() => _defaultInstance ??= create()..freeze();
164 | static UInt32Value _defaultInstance;
165 | static void $checkItem(UInt32Value v) {
166 | if (v is! UInt32Value) $pb.checkItemFailed(v, _i.qualifiedMessageName);
167 | }
168 |
169 | int get value => $_get(0, 0);
170 | set value(int v) { $_setUnsignedInt32(0, v); }
171 | bool hasValue() => $_has(0);
172 | void clearValue() => clearField(1);
173 | }
174 |
175 | class BoolValue extends $pb.GeneratedMessage {
176 | static final $pb.BuilderInfo _i = new $pb.BuilderInfo('BoolValue', package: const $pb.PackageName('google.protobuf'))
177 | ..aOB(1, 'value')
178 | ..hasRequiredFields = false
179 | ;
180 |
181 | BoolValue() : super();
182 | BoolValue.fromBuffer(List i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
183 | BoolValue.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
184 | BoolValue clone() => new BoolValue()..mergeFromMessage(this);
185 | BoolValue copyWith(void Function(BoolValue) updates) => super.copyWith((message) => updates(message as BoolValue));
186 | $pb.BuilderInfo get info_ => _i;
187 | static BoolValue create() => new BoolValue();
188 | BoolValue createEmptyInstance() => create();
189 | static $pb.PbList createRepeated() => new $pb.PbList();
190 | static BoolValue getDefault() => _defaultInstance ??= create()..freeze();
191 | static BoolValue _defaultInstance;
192 | static void $checkItem(BoolValue v) {
193 | if (v is! BoolValue) $pb.checkItemFailed(v, _i.qualifiedMessageName);
194 | }
195 |
196 | bool get value => $_get(0, false);
197 | set value(bool v) { $_setBool(0, v); }
198 | bool hasValue() => $_has(0);
199 | void clearValue() => clearField(1);
200 | }
201 |
202 | class StringValue extends $pb.GeneratedMessage {
203 | static final $pb.BuilderInfo _i = new $pb.BuilderInfo('StringValue', package: const $pb.PackageName('google.protobuf'))
204 | ..aOS(1, 'value')
205 | ..hasRequiredFields = false
206 | ;
207 |
208 | StringValue() : super();
209 | StringValue.fromBuffer(List i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
210 | StringValue.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
211 | StringValue clone() => new StringValue()..mergeFromMessage(this);
212 | StringValue copyWith(void Function(StringValue) updates) => super.copyWith((message) => updates(message as StringValue));
213 | $pb.BuilderInfo get info_ => _i;
214 | static StringValue create() => new StringValue();
215 | StringValue createEmptyInstance() => create();
216 | static $pb.PbList createRepeated() => new $pb.PbList();
217 | static StringValue getDefault() => _defaultInstance ??= create()..freeze();
218 | static StringValue _defaultInstance;
219 | static void $checkItem(StringValue v) {
220 | if (v is! StringValue) $pb.checkItemFailed(v, _i.qualifiedMessageName);
221 | }
222 |
223 | String get value => $_getS(0, '');
224 | set value(String v) { $_setString(0, v); }
225 | bool hasValue() => $_has(0);
226 | void clearValue() => clearField(1);
227 | }
228 |
229 | class BytesValue extends $pb.GeneratedMessage {
230 | static final $pb.BuilderInfo _i = new $pb.BuilderInfo('BytesValue', package: const $pb.PackageName('google.protobuf'))
231 | ..a>(1, 'value', $pb.PbFieldType.OY)
232 | ..hasRequiredFields = false
233 | ;
234 |
235 | BytesValue() : super();
236 | BytesValue.fromBuffer(List i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
237 | BytesValue.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
238 | BytesValue clone() => new BytesValue()..mergeFromMessage(this);
239 | BytesValue copyWith(void Function(BytesValue) updates) => super.copyWith((message) => updates(message as BytesValue));
240 | $pb.BuilderInfo get info_ => _i;
241 | static BytesValue create() => new BytesValue();
242 | BytesValue createEmptyInstance() => create();
243 | static $pb.PbList createRepeated() => new $pb.PbList();
244 | static BytesValue getDefault() => _defaultInstance ??= create()..freeze();
245 | static BytesValue _defaultInstance;
246 | static void $checkItem(BytesValue v) {
247 | if (v is! BytesValue) $pb.checkItemFailed(v, _i.qualifiedMessageName);
248 | }
249 |
250 | List get value => $_getN(0);
251 | set value(List v) { $_setBytes(0, v); }
252 | bool hasValue() => $_has(0);
253 | void clearValue() => clearField(1);
254 | }
255 |
256 |
--------------------------------------------------------------------------------
/flutter_client/lib/api/v1/google/protobuf/wrappers.pbenum.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: wrappers.proto
4 | ///
5 | // ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
6 |
7 |
--------------------------------------------------------------------------------
/flutter_client/lib/api/v1/google/protobuf/wrappers.pbjson.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: wrappers.proto
4 | ///
5 | // ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
6 |
7 | const DoubleValue$json = const {
8 | '1': 'DoubleValue',
9 | '2': const [
10 | const {'1': 'value', '3': 1, '4': 1, '5': 1, '10': 'value'},
11 | ],
12 | };
13 |
14 | const FloatValue$json = const {
15 | '1': 'FloatValue',
16 | '2': const [
17 | const {'1': 'value', '3': 1, '4': 1, '5': 2, '10': 'value'},
18 | ],
19 | };
20 |
21 | const Int64Value$json = const {
22 | '1': 'Int64Value',
23 | '2': const [
24 | const {'1': 'value', '3': 1, '4': 1, '5': 3, '10': 'value'},
25 | ],
26 | };
27 |
28 | const UInt64Value$json = const {
29 | '1': 'UInt64Value',
30 | '2': const [
31 | const {'1': 'value', '3': 1, '4': 1, '5': 4, '10': 'value'},
32 | ],
33 | };
34 |
35 | const Int32Value$json = const {
36 | '1': 'Int32Value',
37 | '2': const [
38 | const {'1': 'value', '3': 1, '4': 1, '5': 5, '10': 'value'},
39 | ],
40 | };
41 |
42 | const UInt32Value$json = const {
43 | '1': 'UInt32Value',
44 | '2': const [
45 | const {'1': 'value', '3': 1, '4': 1, '5': 13, '10': 'value'},
46 | ],
47 | };
48 |
49 | const BoolValue$json = const {
50 | '1': 'BoolValue',
51 | '2': const [
52 | const {'1': 'value', '3': 1, '4': 1, '5': 8, '10': 'value'},
53 | ],
54 | };
55 |
56 | const StringValue$json = const {
57 | '1': 'StringValue',
58 | '2': const [
59 | const {'1': 'value', '3': 1, '4': 1, '5': 9, '10': 'value'},
60 | ],
61 | };
62 |
63 | const BytesValue$json = const {
64 | '1': 'BytesValue',
65 | '2': const [
66 | const {'1': 'value', '3': 1, '4': 1, '5': 12, '10': 'value'},
67 | ],
68 | };
69 |
70 |
--------------------------------------------------------------------------------
/flutter_client/lib/blocs/application_bloc.dart:
--------------------------------------------------------------------------------
1 | import 'dart:collection';
2 |
3 | import 'package:rxdart/rxdart.dart';
4 |
5 | import 'package:flutter_client/models/message.dart';
6 | import 'package:flutter_client/models/message_incoming.dart';
7 | import 'package:flutter_client/models/message_outgoing.dart';
8 |
9 | import 'bloc_provider.dart';
10 | import 'message_events.dart';
11 |
12 | /// BLoC class
13 | class ApplicationBloc implements BlocBase {
14 | // Application state (chat messages)
15 | final _messages = Set();
16 |
17 | /// Controller is used to notify when message created
18 | final _messageCreatedController =
19 | new BehaviorSubject();
20 | Sink get inNewMessageCreated =>
21 | _messageCreatedController.sink;
22 |
23 | /// Controller is used to send message to the server
24 | final _messageSendController = new BehaviorSubject();
25 | Sink get inMessageSend => _messageSendController.sink;
26 | Stream get outMessageSend =>
27 | _messageSendController.stream;
28 |
29 | /// Controller is used to notify when message sent to the server
30 | final _messageSentController = new BehaviorSubject();
31 | Sink get inMessageSent => _messageSentController.sink;
32 |
33 | /// Controller is used to notify when message failed to send to the server
34 | final _messageSendFailedController =
35 | new BehaviorSubject();
36 | Sink get inMessageSendFailed =>
37 | _messageSendFailedController.sink;
38 |
39 | /// Controller is used to notify when message received from the server
40 | final _messageReceivedController =
41 | new BehaviorSubject();
42 | Sink get inMessageReceived =>
43 | _messageReceivedController.sink;
44 |
45 | /// Controller is used to provide state (chat messages) to the widgets
46 | final _messagesController = new BehaviorSubject>(seedValue: []);
47 | Sink> get _inMessages => _messagesController.sink;
48 | Stream> get outMessages => _messagesController.stream;
49 |
50 | /// Constructor
51 | ApplicationBloc() {
52 | _messageCreatedController.listen(_onNewMessageCreated);
53 | _messageSentController.listen(_onMessageSent);
54 | _messageSendFailedController.listen(_onMessageSendFailed);
55 | _messageReceivedController.listen(_onMessageReceived);
56 | }
57 |
58 | /// Dispose resources
59 | void dispose() {
60 | _messageCreatedController.close();
61 | _messageSendController.close();
62 | _messageSentController.close();
63 | _messageSendFailedController.close();
64 | _messageReceivedController.close();
65 | _messagesController.close();
66 | }
67 |
68 | /// Handle event: new message created
69 | void _onNewMessageCreated(MessageNewCreatedEvent event) {
70 | _messages.add(event.message);
71 | _notify();
72 | _messageSendController.add(event);
73 | }
74 |
75 | /// Handle event: message sent to the server
76 | void _onMessageSent(MessageSentEvent event) {
77 | _findOutgoingMessage(event.id).status = MessageOutgoingStatus.SENT;
78 | _notify();
79 | }
80 |
81 | /// Handle event: message failed to send to the server
82 | void _onMessageSendFailed(MessageSendFailedEvent event) {
83 | _findOutgoingMessage(event.id).status = MessageOutgoingStatus.FAILED;
84 | _notify();
85 | }
86 |
87 | /// Handle event: message received from the server
88 | void _onMessageReceived(MessageReceivedEvent event) {
89 | _messages.add(MessageIncoming(text: event.text));
90 | _notify();
91 | }
92 |
93 | /// Publish state (chat messages) to the widgets
94 | void _notify() {
95 | _inMessages.add(UnmodifiableListView(_messages));
96 | }
97 |
98 | /// Find outgoing message by 'id' in the state (chat messages)
99 | MessageOutgoing _findOutgoingMessage(String id) {
100 | var message =
101 | _messages.firstWhere((message) => message.id == id, orElse: () => null);
102 | assert(message != null, 'Sent message with id="$id" is not found in state');
103 | assert(message is MessageOutgoing,
104 | 'Invalid message (id="$id") type ${message.runtimeType}; must be MessageOutgoing');
105 | return message;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/flutter_client/lib/blocs/bloc_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | Type _typeOf() => T;
4 |
5 | abstract class BlocBase {
6 | void dispose();
7 | }
8 |
9 | class BlocProvider extends StatefulWidget {
10 | BlocProvider({
11 | Key key,
12 | @required this.child,
13 | @required this.bloc,
14 | }) : super(key: key);
15 |
16 | final Widget child;
17 | final T bloc;
18 |
19 | @override
20 | _BlocProviderState createState() => _BlocProviderState();
21 |
22 | static T of(BuildContext context) {
23 | final type = _typeOf<_BlocProviderInherited>();
24 | _BlocProviderInherited provider =
25 | context.ancestorInheritedElementForWidgetOfExactType(type)?.widget;
26 | return provider?.bloc;
27 | }
28 | }
29 |
30 | class _BlocProviderState extends State> {
31 | @override
32 | void dispose() {
33 | widget.bloc?.dispose();
34 | super.dispose();
35 | }
36 |
37 | @override
38 | Widget build(BuildContext context) {
39 | return new _BlocProviderInherited(
40 | bloc: widget.bloc,
41 | child: widget.child,
42 | );
43 | }
44 | }
45 |
46 | class _BlocProviderInherited extends InheritedWidget {
47 | _BlocProviderInherited({
48 | Key key,
49 | @required Widget child,
50 | @required this.bloc,
51 | }) : super(key: key, child: child);
52 |
53 | final T bloc;
54 |
55 | @override
56 | bool updateShouldNotify(_BlocProviderInherited oldWidget) => false;
57 | }
58 |
--------------------------------------------------------------------------------
/flutter_client/lib/blocs/message_events.dart:
--------------------------------------------------------------------------------
1 | import 'package:meta/meta.dart';
2 |
3 | import 'package:flutter_client/models/message_outgoing.dart';
4 |
5 | /// New message created event
6 | class MessageNewCreatedEvent {
7 | final MessageOutgoing message;
8 |
9 | MessageNewCreatedEvent({@required this.message});
10 | }
11 |
12 | /// Message sent to the server event
13 | class MessageSentEvent {
14 | final String id;
15 |
16 | MessageSentEvent({@required this.id});
17 | }
18 |
19 | /// Message failed to send to the server event
20 | class MessageSendFailedEvent {
21 | final String id;
22 | final String error;
23 |
24 | MessageSendFailedEvent({@required this.id, @required this.error});
25 | }
26 |
27 | /// Message received from the server event
28 | class MessageReceivedEvent {
29 | final String text;
30 |
31 | MessageReceivedEvent({@required this.text});
32 | }
33 |
34 | /// Message failed to receive from the server event
35 | class MessageReceiveFailedEvent {
36 | final String error;
37 |
38 | MessageReceiveFailedEvent({@required this.error});
39 | }
40 |
--------------------------------------------------------------------------------
/flutter_client/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'package:flutter_client/api/chat_service.dart';
4 |
5 | import 'package:flutter_client/blocs/application_bloc.dart';
6 | import 'package:flutter_client/blocs/bloc_provider.dart';
7 | import 'package:flutter_client/blocs/message_events.dart';
8 |
9 | import 'package:flutter_client/pages/home.dart';
10 |
11 | import 'theme.dart';
12 |
13 | /// main is entry point of Flutter application
14 | void main() {
15 | return runApp(BlocProvider(
16 | bloc: ApplicationBloc(),
17 | child: App(),
18 | ));
19 | }
20 |
21 | // Stateful application widget
22 | class App extends StatefulWidget {
23 | @override
24 | State createState() => _AppState();
25 | }
26 |
27 | // State for application widget
28 | class _AppState extends State {
29 | // BLoc for application
30 | ApplicationBloc _appBloc;
31 |
32 | /// Chat client service
33 | ChatService _service;
34 |
35 | bool _isInit = false;
36 |
37 | @override
38 | void didChangeDependencies() {
39 | super.didChangeDependencies();
40 |
41 | // As the context of not yet available at initState() level,
42 | // if not yet initialized, we get application BLoc to start
43 | // gRPC isolates
44 | if (_isInit == false) {
45 | _appBloc = BlocProvider.of(context);
46 |
47 | // initialize Chat client service
48 | _service = ChatService(
49 | onMessageSent: _onMessageSent,
50 | onMessageSendFailed: _onMessageSendFailed,
51 | onMessageReceived: _onMessageReceived,
52 | onMessageReceiveFailed: _onMessageReceiveFailed);
53 | _service.start();
54 |
55 | _listenMessagesToSend();
56 |
57 | if (mounted) {
58 | setState(() {
59 | _isInit = true;
60 | });
61 | }
62 | }
63 | }
64 |
65 | void _listenMessagesToSend() async {
66 | await for (var event in _appBloc.outMessageSend) {
67 | _service.send(event.message);
68 | }
69 | }
70 |
71 | @override
72 | Widget build(BuildContext context) {
73 | return MaterialApp(
74 | title: 'Friendlychat',
75 | theme: isIOS(context) ? kIOSTheme : kDefaultTheme,
76 | home: HomePage(),
77 | );
78 | }
79 |
80 | @override
81 | void dispose() {
82 | // close Chat client service
83 | _service.shutdown();
84 | _service = null;
85 |
86 | super.dispose();
87 | }
88 |
89 | /// 'outgoing message sent to the server' event
90 | void _onMessageSent(MessageSentEvent event) {
91 | debugPrint('Message "${event.id}" sent to the server');
92 | _appBloc.inMessageSent.add(event);
93 | }
94 |
95 | /// 'failed to send message' event
96 | void _onMessageSendFailed(MessageSendFailedEvent event) {
97 | debugPrint(
98 | 'Failed to send message "${event.id}" to the server: ${event.error}');
99 | _appBloc.inMessageSendFailed.add(event);
100 | }
101 |
102 | /// 'new incoming message received from the server' event
103 | void _onMessageReceived(MessageReceivedEvent event) {
104 | debugPrint('Message received from the server: ${event.text}');
105 | _appBloc.inMessageReceived.add(event);
106 | }
107 |
108 | /// 'failed to receive messages' event
109 | void _onMessageReceiveFailed(MessageReceiveFailedEvent event) {
110 | debugPrint('Failed to receive messages from the server: ${event.error}');
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/flutter_client/lib/models/message.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | /// Message is class defining message data (id and text)
4 | class Message {
5 | /// id is unique ID of message
6 | final String id;
7 |
8 | /// text is content of message
9 | final String text;
10 |
11 | /// Class constructor
12 | Message({String id, @required String text})
13 | : this.id = id ?? UniqueKey().toString(),
14 | this.text = text;
15 | }
16 |
--------------------------------------------------------------------------------
/flutter_client/lib/models/message_incoming.dart:
--------------------------------------------------------------------------------
1 | import 'package:meta/meta.dart';
2 |
3 | import 'message.dart';
4 |
5 | /// MessageIncoming is class defining incoming message data (id and text)
6 | class MessageIncoming extends Message {
7 | /// Constructor
8 | MessageIncoming({String id, @required String text})
9 | : super(id: id, text: text);
10 |
11 | MessageIncoming.copy(MessageIncoming original)
12 | : super(id: original.id, text: original.text);
13 | }
14 |
--------------------------------------------------------------------------------
/flutter_client/lib/models/message_outgoing.dart:
--------------------------------------------------------------------------------
1 | import 'package:meta/meta.dart';
2 |
3 | import 'message.dart';
4 |
5 | /// Outgoing message statuses
6 | /// NEW - message just created and is not sent yet
7 | /// SENT - message is sent to the server successfully
8 | /// FAILED - error has happened while sending message
9 | enum MessageOutgoingStatus { NEW, SENT, FAILED }
10 |
11 | /// MessageOutgoing is class defining outgoing message data (id and text) and status
12 | class MessageOutgoing extends Message {
13 | /// Outgoing message status
14 | MessageOutgoingStatus status;
15 |
16 | /// Constructor
17 | MessageOutgoing(
18 | {String id,
19 | @required String text,
20 | MessageOutgoingStatus status = MessageOutgoingStatus.NEW})
21 | : this.status = status,
22 | super(id: id, text: text);
23 |
24 | MessageOutgoing.copy(MessageOutgoing original)
25 | : this.status = original.status,
26 | super(id: original.id, text: original.text);
27 | }
28 |
--------------------------------------------------------------------------------
/flutter_client/lib/pages/home.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/cupertino.dart';
3 |
4 | import 'package:flutter_client/blocs/application_bloc.dart';
5 | import 'package:flutter_client/blocs/bloc_provider.dart';
6 | import 'package:flutter_client/blocs/message_events.dart';
7 |
8 | import 'package:flutter_client/models/message.dart';
9 | import 'package:flutter_client/models/message_incoming.dart';
10 | import 'package:flutter_client/models/message_outgoing.dart';
11 |
12 | import 'package:flutter_client/theme.dart';
13 |
14 | import 'package:flutter_client/widgets/chat_message.dart';
15 | import 'package:flutter_client/widgets/chat_message_incoming.dart';
16 | import 'package:flutter_client/widgets/chat_message_outgoing.dart';
17 |
18 | /// Host screen widget - main window
19 | class HomePage extends StatefulWidget {
20 | // Constructor
21 | HomePage() : super(key: new ObjectKey("Main window"));
22 |
23 | @override
24 | State createState() => HomePageState();
25 | }
26 |
27 | /// State for main window
28 | class HomePageState extends State with TickerProviderStateMixin {
29 | // BLoc for application
30 | ApplicationBloc _appBloc;
31 |
32 | /// Chat messages list to display into ListView
33 | final List _messages = [];
34 |
35 | /// Look at the https://codelabs.developers.google.com/codelabs/flutter/#4
36 | final TextEditingController _textController = TextEditingController();
37 | bool _isComposing = false;
38 |
39 | bool _isInit = false;
40 |
41 | @override
42 | void didChangeDependencies() {
43 | super.didChangeDependencies();
44 |
45 | // As the context of not yet available at initState() level,
46 | // if not yet initialized, we get the list of all genres
47 | // and retrieve the currently selected one, as well as the
48 | // filter parameters
49 | if (_isInit == false) {
50 | _appBloc = BlocProvider.of(context);
51 | _isInit = true;
52 | }
53 | }
54 |
55 | @override
56 | void dispose() {
57 | // free UI resources
58 | for (ChatMessage message in _messages)
59 | message.animationController.dispose();
60 | super.dispose();
61 | }
62 |
63 | @override
64 | Widget build(BuildContext context) {
65 | return Scaffold(
66 | appBar: AppBar(
67 | title: Text('Friendlychat'),
68 | elevation: isIOS(context) ? 0.0 : 4.0,
69 | ),
70 | body: new Container(
71 | child: new Column(
72 | children: [
73 | Flexible(
74 | child: StreamBuilder(
75 | stream: _appBloc.outMessages,
76 | builder: (BuildContext context,
77 | AsyncSnapshot> snapshot) {
78 | if (snapshot.hasError) {
79 | return Text("Error: ${snapshot.error}");
80 | } else if (snapshot.hasData) {
81 | // update messages according to the data
82 | _updateMessages(snapshot.data);
83 | }
84 | return ListView.builder(
85 | padding: EdgeInsets.all(8.0),
86 | reverse: true,
87 | itemBuilder: (_, int index) => _messages[index],
88 | itemCount: _messages.length);
89 | },
90 | ),
91 | ),
92 | Divider(height: 1.0),
93 | Container(
94 | decoration: BoxDecoration(color: Theme.of(context).cardColor),
95 | child: _buildTextComposer(context),
96 | ),
97 | ],
98 | ),
99 | decoration: isIOS(context)
100 | ? new BoxDecoration(
101 | border: new Border(
102 | top: new BorderSide(color: Colors.grey[200]),
103 | ),
104 | )
105 | : null),
106 | );
107 | }
108 |
109 | /// Look at the https://codelabs.developers.google.com/codelabs/flutter/#4
110 | Widget _buildTextComposer(BuildContext context) {
111 | return IconTheme(
112 | data: IconThemeData(color: Theme.of(context).accentColor),
113 | child: Container(
114 | margin: const EdgeInsets.symmetric(horizontal: 8.0),
115 | child: Row(
116 | children: [
117 | Flexible(
118 | child: isIOS(context)
119 | ? CupertinoTextField(
120 | key: Key('message-text-field'),
121 | maxLines: null,
122 | textInputAction: TextInputAction.send,
123 | controller: _textController,
124 | onChanged: (String text) {
125 | setState(() {
126 | _isComposing = text.length > 0;
127 | });
128 | },
129 | onSubmitted: _isComposing ? _handleSubmitted : null,
130 | )
131 | : TextField(
132 | key: Key('message-text-field'),
133 | maxLines: null,
134 | textInputAction: TextInputAction.send,
135 | controller: _textController,
136 | onChanged: (String text) {
137 | setState(() {
138 | _isComposing = text.length > 0;
139 | });
140 | },
141 | onSubmitted: _isComposing ? _handleSubmitted : null,
142 | decoration:
143 | InputDecoration.collapsed(hintText: "Send a message"),
144 | ),
145 | ),
146 | Container(
147 | margin: EdgeInsets.symmetric(horizontal: 4.0),
148 | child: isIOS(context)
149 | ? new CupertinoButton(
150 | child: new Text("Send"),
151 | onPressed: _isComposing
152 | ? () => _handleSubmitted(_textController.text)
153 | : null,
154 | )
155 | : new IconButton(
156 | key: Key('send-button'),
157 | icon: new Icon(Icons.send),
158 | onPressed: _isComposing
159 | ? () => _handleSubmitted(_textController.text)
160 | : null,
161 | ),
162 | ),
163 | ],
164 | ),
165 | ),
166 | );
167 | }
168 |
169 | /// 'new outgoing message created' event
170 | void _handleSubmitted(String text) {
171 | _textController.clear();
172 | _isComposing = false;
173 |
174 | _appBloc.inNewMessageCreated
175 | .add(MessageNewCreatedEvent(message: MessageOutgoing(text: text)));
176 | }
177 |
178 | /// this methods is called to display new (outgoing or incoming) message or
179 | /// update status of existing outgoing message
180 | void _updateMessages(List messages) {
181 | for (var message in messages) {
182 | int i = _messages.indexWhere((msg) => msg.message.id == message.id);
183 | if (i != -1) {
184 | // existing message
185 | if (message is MessageOutgoing) {
186 | // update existing message
187 | var chatMessage = _messages[i];
188 | if (chatMessage is ChatMessageOutgoing) {
189 | if (chatMessage.message.status != message.status) {
190 | // dispose previous message
191 | chatMessage.animationController.dispose();
192 | // update status for outgoing message
193 | _messages[i] = ChatMessageOutgoing(
194 | message: MessageOutgoing.copy(message),
195 | animationController: AnimationController(
196 | duration: Duration.zero,
197 | vsync: this,
198 | ),
199 | );
200 | }
201 | _messages[i].animationController.forward();
202 | } else {
203 | assert(false, 'Message must be MessageOutcome type');
204 | }
205 | }
206 | } else {
207 | ChatMessage chatMessage;
208 | // new message
209 | var animationController = AnimationController(
210 | duration: Duration(milliseconds: 700),
211 | vsync: this,
212 | );
213 | if (message is MessageOutgoing) {
214 | // add new outgoing message
215 | chatMessage = ChatMessageOutgoing(
216 | message: MessageOutgoing.copy(message),
217 | animationController: animationController,
218 | );
219 | } else if (message is MessageIncoming) {
220 | // add new incoming message
221 | chatMessage = ChatMessageIncoming(
222 | message: MessageIncoming.copy(message),
223 | animationController: animationController,
224 | );
225 | } else {
226 | assert(false, 'Unknown message type ${message.runtimeType}');
227 | }
228 | _messages.insert(0, chatMessage);
229 |
230 | // look at the https://codelabs.developers.google.com/codelabs/flutter/#6
231 | chatMessage.animationController.forward();
232 | }
233 | }
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/flutter_client/lib/theme.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | final ThemeData kIOSTheme = new ThemeData(
4 | primarySwatch: Colors.orange,
5 | primaryColor: Colors.grey[100],
6 | primaryColorBrightness: Brightness.light,
7 | );
8 |
9 | final ThemeData kDefaultTheme = ThemeData.light();
10 | final Color shimmerBaseColor = Colors.black; /*Colors.white;*/
11 | final Color shimmerHighlightColor = Colors.grey[200]; /*Colors.grey[700];*/
12 |
13 | bool isIOS(BuildContext context) {
14 | return Theme.of(context).platform == TargetPlatform.iOS;
15 | }
16 |
--------------------------------------------------------------------------------
/flutter_client/lib/widgets/chat_message.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'package:flutter_client/models/message.dart';
4 |
5 | /// ChatMessage is base abstract class for outgoing and incoming message widgets
6 | abstract class ChatMessage extends Widget {
7 | /// Message content
8 | Message get message;
9 |
10 | /// Controller of animation for message widget
11 | AnimationController get animationController;
12 | }
13 |
--------------------------------------------------------------------------------
/flutter_client/lib/widgets/chat_message_incoming.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'package:flutter_client/models/message_incoming.dart';
4 |
5 | import 'chat_message.dart';
6 |
7 | /// Incoming message author name
8 | const String _server = "Server";
9 |
10 | /// ChatMessageIncoming is widget to display incoming from server message
11 | class ChatMessageIncoming extends StatelessWidget implements ChatMessage {
12 | /// Incoming message content
13 | final MessageIncoming message;
14 |
15 | /// Controller of animation for message widget
16 | final AnimationController animationController;
17 |
18 | /// Constructor
19 | ChatMessageIncoming({this.message, this.animationController})
20 | : super(key: Key(message.id));
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return SizeTransition(
25 | sizeFactor:
26 | CurvedAnimation(parent: animationController, curve: Curves.easeOut),
27 | axisAlignment: 0.0,
28 | child: Container(
29 | margin: EdgeInsets.symmetric(vertical: 10.0),
30 | child: Row(
31 | crossAxisAlignment: CrossAxisAlignment.start,
32 | children: [
33 | Expanded(
34 | child: Column(
35 | crossAxisAlignment: CrossAxisAlignment.end,
36 | children: [
37 | Text(_server, style: Theme.of(context).textTheme.subhead),
38 | Container(
39 | margin: EdgeInsets.only(top: 5.0),
40 | child: Text(message.text),
41 | ),
42 | ],
43 | ),
44 | ),
45 | Container(
46 | margin: EdgeInsets.only(left: 16.0),
47 | child: CircleAvatar(
48 | backgroundColor: Colors.pink.shade600,
49 | child: Text(_server[0])),
50 | ),
51 | ],
52 | ),
53 | ),
54 | );
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/flutter_client/lib/widgets/chat_message_outgoing.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'package:shimmer/shimmer.dart';
4 |
5 | import 'package:flutter_client/models/message_outgoing.dart';
6 | import 'package:flutter_client/theme.dart';
7 |
8 | import 'chat_message.dart';
9 |
10 | /// Outgoing message author name
11 | const String _name = "Me";
12 |
13 | /// ChatMessageOutgoing is widget to display outgoing to server message
14 | class ChatMessageOutgoing extends StatelessWidget implements ChatMessage {
15 | /// Incoming message content
16 | final MessageOutgoing message;
17 |
18 | /// Controller of animation for message widget
19 | final AnimationController animationController;
20 |
21 | /// Constructor
22 | ChatMessageOutgoing({this.message, this.animationController})
23 | : super(key: Key(message.id));
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | return SizeTransition(
28 | sizeFactor:
29 | CurvedAnimation(parent: animationController, curve: Curves.easeOut),
30 | axisAlignment: 0.0,
31 | child: Container(
32 | margin: EdgeInsets.symmetric(vertical: 10.0),
33 | child: Row(
34 | crossAxisAlignment: CrossAxisAlignment.start,
35 | children: [
36 | Container(
37 | margin: EdgeInsets.only(right: 16.0),
38 | child: CircleAvatar(child: Text(_name[0])),
39 | ),
40 | Expanded(
41 | child: _getMessageContent(context),
42 | ),
43 | Container(
44 | child: Icon(message.status == MessageOutgoingStatus.SENT
45 | ? Icons.done
46 | : Icons.access_time),
47 | ),
48 | ],
49 | ),
50 | ),
51 | );
52 | }
53 |
54 | Widget _getMessageContent(BuildContext context) {
55 | var content = Column(
56 | crossAxisAlignment: CrossAxisAlignment.start,
57 | children: [
58 | Text(_name, style: Theme.of(context).textTheme.subhead),
59 | Container(
60 | margin: EdgeInsets.only(top: 5.0),
61 | child: Text(message.text),
62 | ),
63 | ],
64 | );
65 | if (message.status != MessageOutgoingStatus.SENT) {
66 | return Shimmer.fromColors(
67 | baseColor: shimmerBaseColor,
68 | highlightColor: shimmerHighlightColor,
69 | child: content,
70 | );
71 | }
72 | return content;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/flutter_client/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_client
2 | description: Client for tutotrial "How to use gRPC (simple and server-side streaming) within Flutter application".
3 |
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # Read more about versioning at semver.org.
10 | version: 1.0.1+1
11 |
12 | environment:
13 | sdk: ">=2.0.0-dev.68.0 <3.0.0"
14 |
15 | dependencies:
16 | flutter:
17 | sdk: flutter
18 |
19 | # The following adds the Cupertino Icons font to your application.
20 | # Use with the CupertinoIcons class for iOS style icons.
21 | cupertino_icons: ^0.1.2
22 |
23 | grpc: ^1.0.1
24 | protobuf: ^0.13.1
25 |
26 | rxdart: ^0.20.0
27 |
28 | shimmer: ^1.0.0
29 |
30 | dev_dependencies:
31 | flutter_test:
32 | sdk: flutter
33 |
34 |
35 | # For information on the generic Dart part of this file, see the
36 | # following page: https://www.dartlang.org/tools/pub/pubspec
37 |
38 | # The following section is specific to Flutter.
39 | flutter:
40 |
41 | # The following line ensures that the Material Icons font is
42 | # included with your application, so that you can use the icons in
43 | # the material Icons class.
44 | uses-material-design: true
45 |
46 | # To add assets to your application, add an assets section, like this:
47 | # assets:
48 | # - images/a_dot_burr.jpeg
49 | # - images/a_dot_ham.jpeg
50 |
51 | # An image asset can refer to one or more resolution-specific "variants", see
52 | # https://flutter.io/assets-and-images/#resolution-aware.
53 |
54 | # For details regarding adding assets from package dependencies, see
55 | # https://flutter.io/assets-and-images/#from-packages
56 |
57 | # To add custom fonts to your application, add a fonts section here,
58 | # in this "flutter" section. Each entry in this list should have a
59 | # "family" key with the font family name, and a "fonts" key with a
60 | # list giving the asset and other descriptors for the font. For
61 | # example:
62 | # fonts:
63 | # - family: Schyler
64 | # fonts:
65 | # - asset: fonts/Schyler-Regular.ttf
66 | # - asset: fonts/Schyler-Italic.ttf
67 | # style: italic
68 | # - family: Trajan Pro
69 | # fonts:
70 | # - asset: fonts/TrajanPro.ttf
71 | # - asset: fonts/TrajanPro_Bold.ttf
72 | # weight: 700
73 | #
74 | # For details regarding fonts from package dependencies,
75 | # see https://flutter.io/custom-fonts/#from-packages
76 |
--------------------------------------------------------------------------------
/go-server/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, build with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 | /go.sum
--------------------------------------------------------------------------------
/go-server/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Launch",
9 | "type": "go",
10 | "request": "launch",
11 | "mode": "auto",
12 | "program": "${workspaceFolder}/cmd/server/main.go",
13 | "env": {},
14 | "args": []
15 | }
16 | ]
17 | }
--------------------------------------------------------------------------------
/go-server/cmd/server/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "os"
7 |
8 | "github.com/amsokol/flutter-grpc-tutorial/go-server/pkg/protocol/grpc"
9 | "github.com/amsokol/flutter-grpc-tutorial/go-server/pkg/service/v1"
10 | )
11 |
12 | func main() {
13 | if err := grpc.RunServer(context.Background(), v1.NewChatServiceServer(), "3000"); err != nil {
14 | fmt.Fprintf(os.Stderr, "%v\n", err)
15 | os.Exit(1)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/go-server/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/amsokol/flutter-grpc-tutorial/go-server
2 |
3 | require (
4 | github.com/golang/protobuf v1.2.1-0.20190109072247-347cf4a86c1c
5 | golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 // indirect
6 | google.golang.org/grpc v1.18.0
7 | )
8 |
--------------------------------------------------------------------------------
/go-server/pkg/api/v1/chat.pb.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go. DO NOT EDIT.
2 | // source: chat.proto
3 |
4 | package v1
5 |
6 | import (
7 | context "context"
8 | fmt "fmt"
9 | proto "github.com/golang/protobuf/proto"
10 | empty "github.com/golang/protobuf/ptypes/empty"
11 | wrappers "github.com/golang/protobuf/ptypes/wrappers"
12 | grpc "google.golang.org/grpc"
13 | math "math"
14 | )
15 |
16 | // Reference imports to suppress errors if they are not otherwise used.
17 | var _ = proto.Marshal
18 | var _ = fmt.Errorf
19 | var _ = math.Inf
20 |
21 | // This is a compile-time assertion to ensure that this generated file
22 | // is compatible with the proto package it is being compiled against.
23 | // A compilation error at this line likely means your copy of the
24 | // proto package needs to be updated.
25 | const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
26 |
27 | // Message is response for ChatService.Subscribe method
28 | type Message struct {
29 | // message body
30 | Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"`
31 | XXX_NoUnkeyedLiteral struct{} `json:"-"`
32 | XXX_unrecognized []byte `json:"-"`
33 | XXX_sizecache int32 `json:"-"`
34 | }
35 |
36 | func (m *Message) Reset() { *m = Message{} }
37 | func (m *Message) String() string { return proto.CompactTextString(m) }
38 | func (*Message) ProtoMessage() {}
39 | func (*Message) Descriptor() ([]byte, []int) {
40 | return fileDescriptor_8c585a45e2093e54, []int{0}
41 | }
42 |
43 | func (m *Message) XXX_Unmarshal(b []byte) error {
44 | return xxx_messageInfo_Message.Unmarshal(m, b)
45 | }
46 | func (m *Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
47 | return xxx_messageInfo_Message.Marshal(b, m, deterministic)
48 | }
49 | func (m *Message) XXX_Merge(src proto.Message) {
50 | xxx_messageInfo_Message.Merge(m, src)
51 | }
52 | func (m *Message) XXX_Size() int {
53 | return xxx_messageInfo_Message.Size(m)
54 | }
55 | func (m *Message) XXX_DiscardUnknown() {
56 | xxx_messageInfo_Message.DiscardUnknown(m)
57 | }
58 |
59 | var xxx_messageInfo_Message proto.InternalMessageInfo
60 |
61 | func (m *Message) GetText() string {
62 | if m != nil {
63 | return m.Text
64 | }
65 | return ""
66 | }
67 |
68 | func init() {
69 | proto.RegisterType((*Message)(nil), "v1.Message")
70 | }
71 |
72 | func init() { proto.RegisterFile("chat.proto", fileDescriptor_8c585a45e2093e54) }
73 |
74 | var fileDescriptor_8c585a45e2093e54 = []byte{
75 | // 191 bytes of a gzipped FileDescriptorProto
76 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4a, 0xce, 0x48, 0x2c,
77 | 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2a, 0x33, 0x94, 0x92, 0x4e, 0xcf, 0xcf, 0x4f,
78 | 0xcf, 0x49, 0xd5, 0x07, 0x8b, 0x24, 0x95, 0xa6, 0xe9, 0xa7, 0xe6, 0x16, 0x94, 0x54, 0x42, 0x14,
79 | 0x48, 0xc9, 0xa1, 0x4b, 0x96, 0x17, 0x25, 0x16, 0x14, 0xa4, 0x16, 0x15, 0x43, 0xe4, 0x95, 0x64,
80 | 0xb9, 0xd8, 0x7d, 0x53, 0x8b, 0x8b, 0x13, 0xd3, 0x53, 0x85, 0x84, 0xb8, 0x58, 0x4a, 0x52, 0x2b,
81 | 0x4a, 0x24, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0xc0, 0x6c, 0xa3, 0x66, 0x46, 0x2e, 0x6e, 0xe7,
82 | 0x8c, 0xc4, 0x92, 0xe0, 0xd4, 0xa2, 0xb2, 0xcc, 0xe4, 0x54, 0x21, 0x3b, 0x2e, 0x96, 0xe0, 0xd4,
83 | 0xbc, 0x14, 0x21, 0x19, 0x3d, 0x88, 0xb9, 0x7a, 0x30, 0x73, 0xf5, 0x82, 0x4b, 0x8a, 0x32, 0xf3,
84 | 0xd2, 0xc3, 0x12, 0x73, 0x4a, 0x53, 0xa5, 0xc4, 0x30, 0x64, 0x5d, 0x41, 0x4e, 0x52, 0x62, 0x10,
85 | 0x32, 0xe1, 0xe2, 0x0c, 0x2e, 0x4d, 0x2a, 0x4e, 0x2e, 0xca, 0x4c, 0x4a, 0x15, 0xc2, 0xa1, 0x4c,
86 | 0x8a, 0x5b, 0xaf, 0xcc, 0x50, 0x0f, 0xea, 0x2a, 0x25, 0x06, 0x03, 0xc6, 0x24, 0x36, 0xb0, 0x02,
87 | 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfb, 0x39, 0xcd, 0xdf, 0xfa, 0x00, 0x00, 0x00,
88 | }
89 |
90 | // Reference imports to suppress errors if they are not otherwise used.
91 | var _ context.Context
92 | var _ grpc.ClientConn
93 |
94 | // This is a compile-time assertion to ensure that this generated file
95 | // is compatible with the grpc package it is being compiled against.
96 | const _ = grpc.SupportPackageIsVersion4
97 |
98 | // ChatServiceClient is the client API for ChatService service.
99 | //
100 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
101 | type ChatServiceClient interface {
102 | // Send sends message to the server
103 | Send(ctx context.Context, in *wrappers.StringValue, opts ...grpc.CallOption) (*empty.Empty, error)
104 | // Subscribe is streaming method to get echo messages from the server
105 | Subscribe(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (ChatService_SubscribeClient, error)
106 | }
107 |
108 | type chatServiceClient struct {
109 | cc *grpc.ClientConn
110 | }
111 |
112 | func NewChatServiceClient(cc *grpc.ClientConn) ChatServiceClient {
113 | return &chatServiceClient{cc}
114 | }
115 |
116 | func (c *chatServiceClient) Send(ctx context.Context, in *wrappers.StringValue, opts ...grpc.CallOption) (*empty.Empty, error) {
117 | out := new(empty.Empty)
118 | err := c.cc.Invoke(ctx, "/v1.ChatService/Send", in, out, opts...)
119 | if err != nil {
120 | return nil, err
121 | }
122 | return out, nil
123 | }
124 |
125 | func (c *chatServiceClient) Subscribe(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (ChatService_SubscribeClient, error) {
126 | stream, err := c.cc.NewStream(ctx, &_ChatService_serviceDesc.Streams[0], "/v1.ChatService/Subscribe", opts...)
127 | if err != nil {
128 | return nil, err
129 | }
130 | x := &chatServiceSubscribeClient{stream}
131 | if err := x.ClientStream.SendMsg(in); err != nil {
132 | return nil, err
133 | }
134 | if err := x.ClientStream.CloseSend(); err != nil {
135 | return nil, err
136 | }
137 | return x, nil
138 | }
139 |
140 | type ChatService_SubscribeClient interface {
141 | Recv() (*Message, error)
142 | grpc.ClientStream
143 | }
144 |
145 | type chatServiceSubscribeClient struct {
146 | grpc.ClientStream
147 | }
148 |
149 | func (x *chatServiceSubscribeClient) Recv() (*Message, error) {
150 | m := new(Message)
151 | if err := x.ClientStream.RecvMsg(m); err != nil {
152 | return nil, err
153 | }
154 | return m, nil
155 | }
156 |
157 | // ChatServiceServer is the server API for ChatService service.
158 | type ChatServiceServer interface {
159 | // Send sends message to the server
160 | Send(context.Context, *wrappers.StringValue) (*empty.Empty, error)
161 | // Subscribe is streaming method to get echo messages from the server
162 | Subscribe(*empty.Empty, ChatService_SubscribeServer) error
163 | }
164 |
165 | func RegisterChatServiceServer(s *grpc.Server, srv ChatServiceServer) {
166 | s.RegisterService(&_ChatService_serviceDesc, srv)
167 | }
168 |
169 | func _ChatService_Send_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
170 | in := new(wrappers.StringValue)
171 | if err := dec(in); err != nil {
172 | return nil, err
173 | }
174 | if interceptor == nil {
175 | return srv.(ChatServiceServer).Send(ctx, in)
176 | }
177 | info := &grpc.UnaryServerInfo{
178 | Server: srv,
179 | FullMethod: "/v1.ChatService/Send",
180 | }
181 | handler := func(ctx context.Context, req interface{}) (interface{}, error) {
182 | return srv.(ChatServiceServer).Send(ctx, req.(*wrappers.StringValue))
183 | }
184 | return interceptor(ctx, in, info, handler)
185 | }
186 |
187 | func _ChatService_Subscribe_Handler(srv interface{}, stream grpc.ServerStream) error {
188 | m := new(empty.Empty)
189 | if err := stream.RecvMsg(m); err != nil {
190 | return err
191 | }
192 | return srv.(ChatServiceServer).Subscribe(m, &chatServiceSubscribeServer{stream})
193 | }
194 |
195 | type ChatService_SubscribeServer interface {
196 | Send(*Message) error
197 | grpc.ServerStream
198 | }
199 |
200 | type chatServiceSubscribeServer struct {
201 | grpc.ServerStream
202 | }
203 |
204 | func (x *chatServiceSubscribeServer) Send(m *Message) error {
205 | return x.ServerStream.SendMsg(m)
206 | }
207 |
208 | var _ChatService_serviceDesc = grpc.ServiceDesc{
209 | ServiceName: "v1.ChatService",
210 | HandlerType: (*ChatServiceServer)(nil),
211 | Methods: []grpc.MethodDesc{
212 | {
213 | MethodName: "Send",
214 | Handler: _ChatService_Send_Handler,
215 | },
216 | },
217 | Streams: []grpc.StreamDesc{
218 | {
219 | StreamName: "Subscribe",
220 | Handler: _ChatService_Subscribe_Handler,
221 | ServerStreams: true,
222 | },
223 | },
224 | Metadata: "chat.proto",
225 | }
226 |
--------------------------------------------------------------------------------
/go-server/pkg/protocol/grpc/server.go:
--------------------------------------------------------------------------------
1 | package grpc
2 |
3 | import (
4 | "context"
5 | "log"
6 | "net"
7 |
8 | "google.golang.org/grpc"
9 |
10 | "github.com/amsokol/flutter-grpc-tutorial/go-server/pkg/api/v1"
11 | )
12 |
13 | // RunServer registers gRPC service and run server
14 | func RunServer(ctx context.Context, srv v1.ChatServiceServer, port string) error {
15 | listen, err := net.Listen("tcp", ":"+port)
16 | if err != nil {
17 | return err
18 | }
19 |
20 | // register service
21 | server := grpc.NewServer()
22 | v1.RegisterChatServiceServer(server, srv)
23 |
24 | // start gRPC server
25 | log.Println("starting gRPC server...")
26 | return server.Serve(listen)
27 | }
28 |
--------------------------------------------------------------------------------
/go-server/pkg/service/v1/chat.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "log"
7 |
8 | "github.com/golang/protobuf/ptypes/empty"
9 | "github.com/golang/protobuf/ptypes/wrappers"
10 |
11 | "github.com/amsokol/flutter-grpc-tutorial/go-server/pkg/api/v1"
12 | )
13 |
14 | // chatServiceServer is implementation of v1.ChatServiceServer proto interface
15 | type chatServiceServer struct {
16 | msg chan string
17 | }
18 |
19 | // NewChatServiceServer creates Chat service object
20 | func NewChatServiceServer() v1.ChatServiceServer {
21 | return &chatServiceServer{msg: make(chan string, 1000)}
22 | }
23 |
24 | // Send sends message to the server
25 | func (s *chatServiceServer) Send(ctx context.Context, message *wrappers.StringValue) (*empty.Empty, error) {
26 | if message != nil {
27 | log.Printf("Send requested: message=%v", *message)
28 | s.msg <- message.Value
29 | } else {
30 | log.Print("Send requested: message=")
31 | }
32 |
33 | return &empty.Empty{}, nil
34 | }
35 |
36 | // Subscribe is streaming method to get echo messages from the server
37 | func (s *chatServiceServer) Subscribe(e *empty.Empty, stream v1.ChatService_SubscribeServer) error {
38 | log.Print("Subscribe requested")
39 | for {
40 | m := <-s.msg
41 | n := v1.Message{Text: fmt.Sprintf("I have received from you: %s. Thanks!", m)}
42 | if err := stream.Send(&n); err != nil {
43 | // put message back to the channel
44 | s.msg <- m
45 | log.Printf("Stream connection failed: %v", err)
46 | return nil
47 | }
48 | log.Printf("Message sent: %+v", n)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/third_party/google/protobuf/empty.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | syntax = "proto3";
32 |
33 | package google.protobuf;
34 |
35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
36 | option go_package = "github.com/golang/protobuf/ptypes/empty";
37 | option java_package = "com.google.protobuf";
38 | option java_outer_classname = "EmptyProto";
39 | option java_multiple_files = true;
40 | option objc_class_prefix = "GPB";
41 | option cc_enable_arenas = true;
42 |
43 | // A generic empty message that you can re-use to avoid defining duplicated
44 | // empty messages in your APIs. A typical example is to use it as the request
45 | // or the response type of an API method. For instance:
46 | //
47 | // service Foo {
48 | // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
49 | // }
50 | //
51 | // The JSON representation for `Empty` is empty JSON object `{}`.
52 | message Empty {}
53 |
--------------------------------------------------------------------------------
/third_party/google/protobuf/timestamp.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | syntax = "proto3";
32 |
33 | package google.protobuf;
34 |
35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
36 | option cc_enable_arenas = true;
37 | option go_package = "github.com/golang/protobuf/ptypes/timestamp";
38 | option java_package = "com.google.protobuf";
39 | option java_outer_classname = "TimestampProto";
40 | option java_multiple_files = true;
41 | option objc_class_prefix = "GPB";
42 |
43 | // A Timestamp represents a point in time independent of any time zone
44 | // or calendar, represented as seconds and fractions of seconds at
45 | // nanosecond resolution in UTC Epoch time. It is encoded using the
46 | // Proleptic Gregorian Calendar which extends the Gregorian calendar
47 | // backwards to year one. It is encoded assuming all minutes are 60
48 | // seconds long, i.e. leap seconds are "smeared" so that no leap second
49 | // table is needed for interpretation. Range is from
50 | // 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
51 | // By restricting to that range, we ensure that we can convert to
52 | // and from RFC 3339 date strings.
53 | // See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
54 | //
55 | // # Examples
56 | //
57 | // Example 1: Compute Timestamp from POSIX `time()`.
58 | //
59 | // Timestamp timestamp;
60 | // timestamp.set_seconds(time(NULL));
61 | // timestamp.set_nanos(0);
62 | //
63 | // Example 2: Compute Timestamp from POSIX `gettimeofday()`.
64 | //
65 | // struct timeval tv;
66 | // gettimeofday(&tv, NULL);
67 | //
68 | // Timestamp timestamp;
69 | // timestamp.set_seconds(tv.tv_sec);
70 | // timestamp.set_nanos(tv.tv_usec * 1000);
71 | //
72 | // Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
73 | //
74 | // FILETIME ft;
75 | // GetSystemTimeAsFileTime(&ft);
76 | // UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
77 | //
78 | // // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
79 | // // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
80 | // Timestamp timestamp;
81 | // timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
82 | // timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
83 | //
84 | // Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
85 | //
86 | // long millis = System.currentTimeMillis();
87 | //
88 | // Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
89 | // .setNanos((int) ((millis % 1000) * 1000000)).build();
90 | //
91 | //
92 | // Example 5: Compute Timestamp from current time in Python.
93 | //
94 | // timestamp = Timestamp()
95 | // timestamp.GetCurrentTime()
96 | //
97 | // # JSON Mapping
98 | //
99 | // In JSON format, the Timestamp type is encoded as a string in the
100 | // [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
101 | // format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
102 | // where {year} is always expressed using four digits while {month}, {day},
103 | // {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
104 | // seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
105 | // are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
106 | // is required. A proto3 JSON serializer should always use UTC (as indicated by
107 | // "Z") when printing the Timestamp type and a proto3 JSON parser should be
108 | // able to accept both UTC and other timezones (as indicated by an offset).
109 | //
110 | // For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
111 | // 01:30 UTC on January 15, 2017.
112 | //
113 | // In JavaScript, one can convert a Date object to this format using the
114 | // standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
115 | // method. In Python, a standard `datetime.datetime` object can be converted
116 | // to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
117 | // with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
118 | // can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
119 | // http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--
120 | // ) to obtain a formatter capable of generating timestamps in this format.
121 | //
122 | //
123 | message Timestamp {
124 |
125 | // Represents seconds of UTC time since Unix epoch
126 | // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
127 | // 9999-12-31T23:59:59Z inclusive.
128 | int64 seconds = 1;
129 |
130 | // Non-negative fractions of a second at nanosecond resolution. Negative
131 | // second values with fractions must still have non-negative nanos values
132 | // that count forward in time. Must be from 0 to 999,999,999
133 | // inclusive.
134 | int32 nanos = 2;
135 | }
136 |
--------------------------------------------------------------------------------
/third_party/google/protobuf/wrappers.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | // Wrappers for primitive (non-message) types. These types are useful
32 | // for embedding primitives in the `google.protobuf.Any` type and for places
33 | // where we need to distinguish between the absence of a primitive
34 | // typed field and its default value.
35 |
36 | syntax = "proto3";
37 |
38 | package google.protobuf;
39 |
40 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
41 | option cc_enable_arenas = true;
42 | option go_package = "github.com/golang/protobuf/ptypes/wrappers";
43 | option java_package = "com.google.protobuf";
44 | option java_outer_classname = "WrappersProto";
45 | option java_multiple_files = true;
46 | option objc_class_prefix = "GPB";
47 |
48 | // Wrapper message for `double`.
49 | //
50 | // The JSON representation for `DoubleValue` is JSON number.
51 | message DoubleValue {
52 | // The double value.
53 | double value = 1;
54 | }
55 |
56 | // Wrapper message for `float`.
57 | //
58 | // The JSON representation for `FloatValue` is JSON number.
59 | message FloatValue {
60 | // The float value.
61 | float value = 1;
62 | }
63 |
64 | // Wrapper message for `int64`.
65 | //
66 | // The JSON representation for `Int64Value` is JSON string.
67 | message Int64Value {
68 | // The int64 value.
69 | int64 value = 1;
70 | }
71 |
72 | // Wrapper message for `uint64`.
73 | //
74 | // The JSON representation for `UInt64Value` is JSON string.
75 | message UInt64Value {
76 | // The uint64 value.
77 | uint64 value = 1;
78 | }
79 |
80 | // Wrapper message for `int32`.
81 | //
82 | // The JSON representation for `Int32Value` is JSON number.
83 | message Int32Value {
84 | // The int32 value.
85 | int32 value = 1;
86 | }
87 |
88 | // Wrapper message for `uint32`.
89 | //
90 | // The JSON representation for `UInt32Value` is JSON number.
91 | message UInt32Value {
92 | // The uint32 value.
93 | uint32 value = 1;
94 | }
95 |
96 | // Wrapper message for `bool`.
97 | //
98 | // The JSON representation for `BoolValue` is JSON `true` and `false`.
99 | message BoolValue {
100 | // The bool value.
101 | bool value = 1;
102 | }
103 |
104 | // Wrapper message for `string`.
105 | //
106 | // The JSON representation for `StringValue` is JSON string.
107 | message StringValue {
108 | // The string value.
109 | string value = 1;
110 | }
111 |
112 | // Wrapper message for `bytes`.
113 | //
114 | // The JSON representation for `BytesValue` is JSON string.
115 | message BytesValue {
116 | // The bytes value.
117 | bytes value = 1;
118 | }
119 |
--------------------------------------------------------------------------------
/third_party/protoc-gen.cmd:
--------------------------------------------------------------------------------
1 | @echo Compiling proto file(s)...
2 |
3 | @protoc empty.proto timestamp.proto wrappers.proto ^
4 | --proto_path=../third_party/google/protobuf ^
5 | --plugin=protoc-gen-dart=%USERPROFILE%/AppData/Roaming/Pub/Cache/bin/protoc-gen-dart.bat ^
6 | --dart_out=grpc:../flutter_client/lib/api/v1/google/protobuf
7 |
8 | @protoc chat.proto ^
9 | --proto_path=../api/proto/v1 ^
10 | --proto_path=. ^
11 | --go_out=plugins=grpc:../go-server/pkg/api/v1
12 |
13 | @protoc chat.proto ^
14 | --proto_path=../api/proto/v1 ^
15 | --proto_path=. ^
16 | --plugin=protoc-gen-dart=%USERPROFILE%/AppData/Roaming/Pub/Cache/bin/protoc-gen-dart.bat ^
17 | --dart_out=grpc:../flutter_client/lib/api/v1
18 |
19 | @echo Done
--------------------------------------------------------------------------------