├── .gitignore
├── .metadata
├── README.md
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ ├── google-services.json
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── etechviral
│ │ │ │ └── group_chat_room_responsive
│ │ │ │ └── MainActivity.kt
│ │ └── 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
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
├── background_img.png
├── bubble.json
├── congratulation.json
├── img.json
├── loading.json
├── logo.png
├── profile.png
├── profile_default.png
└── shape.png
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── Runner
│ ├── AppDelegate.swift
│ ├── 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
│ └── Runner-Bridging-Header.h
├── lib
├── data
│ ├── datasource
│ │ └── firebase_remote_datasource.dart
│ ├── model
│ │ ├── text_message_model.dart
│ │ └── user_model.dart
│ └── repositories
│ │ └── firebasee_repository_impl.dart
├── domain
│ ├── entities
│ │ ├── text_message_entity.dart
│ │ └── user_entity.dart
│ ├── repositories
│ │ └── firebase_repository.dart
│ └── usecase
│ │ ├── get_create_current_user.dart
│ │ ├── get_current_uid.dart
│ │ ├── get_messages_usecase.dart
│ │ ├── get_useres_usecase.dart
│ │ ├── is_signin_usecase.dart
│ │ ├── send_text_message_usecase.dart
│ │ ├── sign_out_usecase.dart
│ │ ├── signin_usecase.dart
│ │ └── signup_usecase.dart
├── injection_container.dart
├── main.dart
└── presentation
│ ├── bloc
│ ├── auth
│ │ ├── auth_cubit.dart
│ │ └── auth_state.dart
│ ├── communication
│ │ ├── communication_cubit.dart
│ │ └── communication_state.dart
│ ├── login
│ │ ├── login_cubit.dart
│ │ └── login_state.dart
│ └── user
│ │ ├── user_cubit.dart
│ │ └── user_state.dart
│ ├── pages
│ ├── mobile
│ │ ├── mobile_page.dart
│ │ ├── single_chat_page_mobile.dart
│ │ ├── welcome_page_mobile.dart
│ │ └── widget
│ │ │ ├── body_widget.dart
│ │ │ └── mobile_message_layout.dart
│ ├── tablet
│ │ ├── single_chat_page_tablet.dart
│ │ ├── tablet_page.dart
│ │ ├── welcome_page_tablet.dart
│ │ └── widgets
│ │ │ ├── left_side_widget.dart
│ │ │ └── right_side_widget.dart
│ ├── web
│ │ ├── single_chat_page_web.dart
│ │ ├── web_page.dart
│ │ ├── welcome_page_web.dart
│ │ └── widgets
│ │ │ ├── left_side_widget.dart
│ │ │ └── right_side_widget.dart
│ └── widget
│ │ └── message_layout.dart
│ └── screens
│ ├── home_screen.dart
│ ├── single_chat_screen.dart
│ └── welcome_screen.dart
├── pubspec.lock
├── pubspec.yaml
├── test
└── widget_test.dart
└── web
├── favicon.png
├── icons
├── Icon-192.png
└── Icon-512.png
├── index.html
└── manifest.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
--------------------------------------------------------------------------------
/.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: 4732a214a7362a3781989977429f14202143b4f5
8 | channel: master
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flutter Responsive Group Chat room (firebase + clean architecture) [Web, Mobile, Tablet]
2 |
3 | ### Show some and star the repo to support the project
4 |
5 |
6 |
7 | ### Preview
8 |
9 | 
10 | 
11 |
12 | ### Screenshots
13 | ### Web
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | ### Mobile
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | Flutter Responsive Group Chat Room (with Firebase + Clean Architecture) complete course
43 |
44 |
45 |
46 | ### How to Create a Flutter Web project
47 |
48 |
49 |
50 | switch to the master channel run the following command
51 |
52 | ``1. flutter channel master``
53 | Then upgrade your flutter to the latest version from master.
54 | `` 2. flutter upgrade``
55 | Then enable web support.
56 | `` 3. flutter config --enable-web``
57 |
58 | Now when you create a project it'll be web enabled and you can run it in the browser. to verify that run this cmd.
59 |
60 | ``flutter devices``
61 |
62 |
63 | Then
64 | ``flutter create xyz_project_name``
65 |
66 |
67 | ### Packages
68 |
69 | [responsive_builder :](https://pub.dev/packages/responsive_builder) The responsive builder package contains widgets that allows you to create a readable responsive UI. The package is inspired by the Responsive UI Flutter series created by FilledStacks.
70 |
71 | [flutter_bloc :](https://pub.dev/packages/flutter_bloc) Widgets that make it easy to integrate blocs and cubits into [Flutter](https://flutter.dev/). Built to work with [package:bloc](https://pub.dev/packages/bloc). The Bloc library provides very good 🦄 tooling and compared to other state management solutions that use Streams, it's a pure gem.
72 |
73 | [get_it :](https://pub.dev/packages/get_it) This is a simple **Service Locator** for Dart and Flutter projects with some additional goodies highly inspired by [Splat](https://github.com/reactiveui/splat). It can be used instead of `InheritedWidget` or `Provider` to access objects e.g. from your UI.
74 |
75 | [equatable:](https://pub.dev/packages/equatable) Being able to compare objects in `Dart` often involves having to override the `==` operator as well as `hashCode`.
76 |
77 | [firebase :](https://firebase.google.com/) is the most amazing back-end as a service (BaaS) developed by Google for mobile and web application development that helps you build, improve, grow your app and deliver richer app experiences.
78 |
79 |
80 | ### # The Clean Architecture [proposed by our friendly Uncle Bob](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)
81 |
82 |
83 |
84 |
85 |
86 |
87 | [@AmirKhan](https://github.com/amirk3321) , Youtube : [@eTechViral](https://www.youtube.com/channel/UCO6gMNHYhRqyzbskNh4gG_A) , Twitter : [@AmirKhan](https://twitter.com/__Meer___)
88 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 |
--------------------------------------------------------------------------------
/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 plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 29
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | lintOptions {
36 | disable 'InvalidPackage'
37 | }
38 |
39 | defaultConfig {
40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
41 | applicationId "com.etechviral.group_chat_room_responsive"
42 | minSdkVersion 16
43 | targetSdkVersion 29
44 | versionCode flutterVersionCode.toInteger()
45 | versionName flutterVersionName
46 | multiDexEnabled true
47 | }
48 |
49 | buildTypes {
50 | release {
51 | // TODO: Add your own signing config for the release build.
52 | // Signing with the debug keys for now, so `flutter run --release` works.
53 | signingConfig signingConfigs.debug
54 | }
55 | }
56 | }
57 |
58 | flutter {
59 | source '../..'
60 | }
61 |
62 | dependencies {
63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
64 | }
65 | apply plugin: 'com.google.gms.google-services'
--------------------------------------------------------------------------------
/android/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "112386489891",
4 | "firebase_url": "https://groupchatroomresponsive.firebaseio.com",
5 | "project_id": "groupchatroomresponsive",
6 | "storage_bucket": "groupchatroomresponsive.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:112386489891:android:2ce216ec89b8b9ca2f3b96",
12 | "android_client_info": {
13 | "package_name": "com.etechviral.group_chat_room_responsive"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "112386489891-o9j4fif092a5ccur03cs0fbaub10hbbk.apps.googleusercontent.com",
19 | "client_type": 3
20 | }
21 | ],
22 | "api_key": [
23 | {
24 | "current_key": "AIzaSyBgHLtSxgpgP49CCIyQ1uJmGEkcU_AsQcQ"
25 | }
26 | ],
27 | "services": {
28 | "appinvite_service": {
29 | "other_platform_oauth_client": [
30 | {
31 | "client_id": "112386489891-o9j4fif092a5ccur03cs0fbaub10hbbk.apps.googleusercontent.com",
32 | "client_type": 3
33 | }
34 | ]
35 | }
36 | }
37 | }
38 | ],
39 | "configuration_version": "1"
40 | }
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
12 |
19 |
23 |
27 |
32 |
36 |
37 |
38 |
39 |
40 |
41 |
43 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/etechviral/group_chat_room_responsive/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.etechviral.group_chat_room_responsive
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.5.0'
10 | classpath 'com.google.gms:google-services:4.3.3'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | }
20 | }
21 |
22 | rootProject.buildDir = '../build'
23 | subprojects {
24 | project.buildDir = "${rootProject.buildDir}/${project.name}"
25 | }
26 | subprojects {
27 | project.evaluationDependsOn(':app')
28 | }
29 |
30 | task clean(type: Delete) {
31 | delete rootProject.buildDir
32 | }
33 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 | android.enableR8=true
5 |
--------------------------------------------------------------------------------
/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-5.6.2-all.zip
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/assets/background_img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/assets/background_img.png
--------------------------------------------------------------------------------
/assets/bubble.json:
--------------------------------------------------------------------------------
1 | {"v":"5.6.5","fr":25,"ip":0,"op":200,"w":1000,"h":1000,"nm":"ballz","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":51,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[478,502.5,0],"to":[-9.667,-0.417,0],"ti":[17.333,-1.083,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":23,"s":[420,500,0],"to":[-17.333,1.083,0],"ti":[6.25,-6.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":43,"s":[374,509,0],"to":[-6.25,6.667,0],"ti":[-10.667,-8.167,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":58,"s":[382.5,540,0],"to":[10.667,8.167,0],"ti":[-19.917,0.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":70,"s":[438,558,0],"to":[19.917,-0.667,0],"ti":[-2.667,6,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81,"s":[502,536,0],"to":[2.667,-6,0],"ti":[12.75,1.5,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88,"s":[454,522,0],"to":[-12.75,-1.5,0],"ti":[5.333,-3.333,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104,"s":[425.5,527,0],"to":[-5.333,3.333,0],"ti":[-9,-6.917,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":111,"s":[422,542,0],"to":[9,6.917,0],"ti":[-8.333,1.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":121,"s":[479.5,568.5,0],"to":[8.333,-1.667,0],"ti":[-11,7.167,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":131,"s":[472,532,0],"to":[11,-7.167,0],"ti":[-9.5,4.417,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":145,"s":[545.5,525.5,0],"to":[9.5,-4.417,0],"ti":[3.917,-1.75,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":157,"s":[529,505.5,0],"to":[-3.917,1.75,0],"ti":[8.25,0.25,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":178,"s":[522,536,0],"to":[-8.25,-0.25,0],"ti":[7.083,5.333,0]},{"t":199,"s":[479.5,504,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[294,274],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.654901960784,0.796078431373,0.850980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[241,-357],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":200,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":51,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[545.25,483.5,0],"to":[5.458,-4.25,0],"ti":[-20.458,-0.75,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":23,"s":[578,458,0],"to":[20.458,0.75,0],"ti":[-19.333,-12.917,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":45,"s":[668,488,0],"to":[19.333,12.917,0],"ti":[1.083,-3.5,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[694,535.5,0],"to":[-0.403,1.303,0],"ti":[5.23,5.938,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":70,"s":[655.624,535.627,0],"to":[-8.823,-10.017,0],"ti":[-19.906,2.756,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88,"s":[667,509.5,0],"to":[11.075,-1.533,0],"ti":[-9.167,-13.083,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":110,"s":[728,538,0],"to":[9.167,13.083,0],"ti":[7.667,-7.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":131,"s":[722,588,0],"to":[-7.667,7.667,0],"ti":[9.333,7.333,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":144,"s":[682,584,0],"to":[-9.333,-7.333,0],"ti":[14,6.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":157,"s":[666,544,0],"to":[-14,-6.667,0],"ti":[20.167,10.083,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":178,"s":[598,544,0],"to":[-20.167,-10.083,0],"ti":[-5.625,13.708,0]},{"t":199,"s":[545,483.5,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[166,164],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.654901960784,0.796078431373,0.850980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-135,166],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[208.434,207.5],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":200,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":51,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[488,483.5,0],"to":[3.5,-12.75,0],"ti":[17.333,7.333,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":23,"s":[470,452,0],"to":[-10.245,-4.334,0],"ti":[16.399,-1.959,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":36,"s":[428.007,456.366,0],"to":[-11.346,1.355,0],"ti":[7.77,-2.863,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":45,"s":[396,456,0],"to":[-19,7,0],"ti":[-0.333,-13.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[356,494,0],"to":[0.333,13.667,0],"ti":[-11,1,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88,"s":[398,538,0],"to":[11,-1,0],"ti":[-11.083,1.083,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109,"s":[422,488,0],"to":[11.083,-1.083,0],"ti":[-1.667,-15.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":131,"s":[464.5,531.5,0],"to":[1.667,15.667,0],"ti":[-3.333,-10.333,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":145,"s":[432,582,0],"to":[3.333,10.333,0],"ti":[-0.667,6.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":157,"s":[484.5,593.5,0],"to":[0.667,-6.667,0],"ti":[-0.583,18.583,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":177,"s":[436,542,0],"to":[0.583,-18.583,0],"ti":[1.833,25.417,0]},{"t":199,"s":[488,482,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[142,138],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.654901960784,0.796078431373,0.850980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[193,-99],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":200,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":51,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[500,500,0],"to":[-3.333,6.667,0],"ti":[-5,-12.333,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":28,"s":[480,540,0],"to":[5,12.333,0],"ti":[-11.667,2,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[530,574,0],"to":[11.667,-2,0],"ti":[-4,16.333,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81,"s":[550,528,0],"to":[4,-16.333,0],"ti":[-10,7.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104,"s":[554,476,0],"to":[10,-7.667,0],"ti":[-9,7.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":121,"s":[610,482,0],"to":[9,-7.667,0],"ti":[9.667,6.333,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":138,"s":[608,430,0],"to":[-9.667,-6.333,0],"ti":[3,-12.333,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":151,"s":[552,444,0],"to":[-3,12.333,0],"ti":[8,-9.333,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":174,"s":[590,504,0],"to":[-8,9.333,0],"ti":[14.333,0.667,0]},{"t":199,"s":[504,500,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[310,310],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.654901960784,0.796078431373,0.850980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-233,-223],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":200,"st":0,"bm":0}],"markers":[]}
--------------------------------------------------------------------------------
/assets/congratulation.json:
--------------------------------------------------------------------------------
1 | {"v":"5.7.0","fr":29.9700012207031,"ip":0,"op":90.0000036657751,"w":800,"h":280,"nm":"바보","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,179,0],"ix":2},"a":{"a":0,"k":[-367,39,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.455,0.455,0.667],"y":[1.003,1.003,1]},"o":{"x":[0.028,0.028,0.333],"y":[1.519,1.519,0]},"t":0,"s":[0,0,100]},{"t":41.0000016699642,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-46,-10],[-6,24]],"o":[[0,0],[46,10],[6,-24]],"v":[[-366,38],[-284,-2],[-214,-26]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.995294129615,0.69033873315,0.284927338245,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":9,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"L_하늘 작은원","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[275.335,64.716,0],"ix":2},"a":{"a":0,"k":[6.913,6.914,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.035,0.035,0.667],"y":[1.362,1.362,1]},"o":{"x":[0.008,0.008,0.333],"y":[1.31,1.31,0]},"t":3,"s":[0,0,100]},{"t":48.0000019550801,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[2.076,-2.534],[2.534,2.076],[-2.075,2.535],[-2.533,-2.076]],"o":[[-2.076,2.534],[-2.534,-2.076],[2.076,-2.533],[2.534,2.075]],"v":[[4.588,3.758],[-3.758,4.588],[-4.589,-3.759],[3.758,-4.588]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.579999976065,0.855000035903,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.913,6.914],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"L_주황원","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[83.223,248.127,0],"ix":2},"a":{"a":0,"k":[8.312,8.313,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.15,0.15,0.667],"y":[1.281,1.281,1]},"o":{"x":[0.008,0.008,0.333],"y":[1.556,1.556,0]},"t":3,"s":[0,0,100]},{"t":48.0000019550801,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.3,-4.287],[4.287,0.301],[-0.301,4.286],[-4.287,-0.3]],"o":[[-0.3,4.287],[-4.286,-0.301],[0.3,-4.288],[4.287,0.301]],"v":[[7.762,0.543],[-0.544,7.761],[-7.761,-0.543],[0.544,-7.762]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.666999966491,0.224000010771,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[8.312,8.313],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"L_구불초록","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[173.967,224.639,0],"ix":2},"a":{"a":0,"k":[49.171,23.215,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.198,0.198,0.667],"y":[1.264,1.264,1]},"o":{"x":[0.007,0.007,0.333],"y":[2.046,2.046,0]},"t":3,"s":[0,0,100]},{"t":48.0000019550801,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-23.191,5.575],[-13.242,-16.528]],"o":[[0,0],[23.19,-5.575],[0,0]],"v":[[-40.223,-8.177],[-4.986,2.692],[40.223,8.26]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.246999987434,1,0.776000019148,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8.379,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[61.171,29.215],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"L_네모 핑크","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[213.323,41.8,0],"ix":2},"a":{"a":0,"k":[27.087,13.782,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.034,0.034,0.667],"y":[1.395,1.395,1]},"o":{"x":[0.045,0.045,0.333],"y":[1.911,1.911,0]},"t":3,"s":[0,0,100]},{"t":48.0000019550801,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.026,-0.378],[0,0],[-0.727,0.32],[-14.856,-9.275],[-0.283,0.564],[0,0],[0.558,0.239],[23.944,-11.679]],"o":[[0,0],[-0.056,0.793],[6.262,-2.76],[0.535,0.335],[0,0],[0.273,-0.543],[-4.956,-2.117],[-0.341,0.166]],"v":[[-25.861,-0.969],[-26.781,12.17],[-25.31,13.212],[19.094,10.582],[20.615,10.177],[26.564,-1.691],[26.044,-3.131],[-25.265,-1.852]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.952999997606,0.579999976065,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[27.087,13.782],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"L_네모 보라","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[99.071,205.298,0],"ix":2},"a":{"a":0,"k":[5.757,24.766,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.086,0.086,0.667],"y":[1.129,1.129,1]},"o":{"x":[0.007,0.007,0.333],"y":[1.458,1.458,0]},"t":3,"s":[0,0,100]},{"t":48.0000019550801,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.034,-0.479],[0,0],[-0.674,0.082],[0,0],[-0.036,0.516],[0,0],[0.703,-0.152],[0,0]],"o":[[0,0],[-0.048,0.677],[0,0],[0.513,-0.063],[0,0],[0.05,-0.718],[0,0],[-0.47,0.101]],"v":[[-18.27,-4.705],[-19.46,12.287],[-18.253,13.434],[17.085,9.129],[18.031,8.133],[19.458,-12.233],[18.152,-13.364],[-17.421,-5.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.709999952129,0.694000004787,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[19.758,13.766],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"L_네모 하늘","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[103.245,56.206,0],"ix":2},"a":{"a":0,"k":[18.443,31.294,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.153,0.153,0.667],"y":[1.127,1.127,1]},"o":{"x":[0.008,0.008,0.333],"y":[1.529,1.529,0]},"t":3,"s":[0,0,100]},{"t":48.0000019550801,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.059,0.411],[-9.703,14.021],[-0.246,-0.009],[0,0],[0.158,-0.452],[-1.201,-12.74],[0.434,0.03],[0,0]],"o":[[0.853,-5.952],[0.14,-0.203],[0,0],[0.478,0.019],[-2.283,6.557],[0.04,0.434],[0,0],[-0.414,-0.029]],"v":[[-18.134,28.815],[-1.617,-30.732],[-0.997,-31.035],[17.388,-30.305],[18.035,-29.362],[3.15,30.252],[2.39,31.014],[-17.476,29.622]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.666999966491,0.870999983245,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[18.443,31.294],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"R_하늘 작은원","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[706.334,124.716,0],"ix":2},"a":{"a":0,"k":[6.913,6.914,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.469,0.469,0.667],"y":[1,1,1]},"o":{"x":[0.02,0.02,0.333],"y":[1.991,1.991,0]},"t":5,"s":[0,0,100]},{"t":50.0000020365418,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[2.075,-2.534],[2.535,2.076],[-2.075,2.535],[-2.534,-2.076]],"o":[[-2.076,2.534],[-2.534,-2.076],[2.076,-2.533],[2.534,2.075]],"v":[[4.589,3.758],[-3.759,4.588],[-4.588,-3.759],[3.759,-4.588]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.579999976065,0.855000035903,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.913,6.914],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"R_하늘 원","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[596.5,17.5,0],"ix":2},"a":{"a":0,"k":[10.25,10.25,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.469,0.469,0.667],"y":[1,1,1]},"o":{"x":[0.02,0.02,0.333],"y":[1.991,1.991,0]},"t":0,"s":[0,0,100]},{"t":45.0000018328876,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-5.523],[5.522,0],[0,5.523],[-5.522,0]],"o":[[0,5.523],[-5.522,0],[0,-5.523],[5.522,0]],"v":[[10,0],[0,10],[-10,0],[0,-10]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.579999976065,0.855000035903,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[10.25,10.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"R_노랑 원","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[598,190,0],"ix":2},"a":{"a":0,"k":[5.75,5.75,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.469,0.469,0.667],"y":[1,1,1]},"o":{"x":[0.02,0.02,0.333],"y":[1.991,1.991,0]},"t":3,"s":[0,0,100]},{"t":48.0000019550801,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-3.038],[3.037,0],[0,3.038],[-3.037,0]],"o":[[0,3.038],[-3.037,0],[0,-3.038],[3.037,0]],"v":[[5.5,0],[0,5.5],[-5.5,0],[0,-5.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.917999985639,0.62400004069,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[5.75,5.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"R_구불핑ㅋ","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-12.353,"ix":10},"p":{"a":0,"k":[704,192.5,0],"ix":2},"a":{"a":0,"k":[112.5,120,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.469,0.469,0.667],"y":[1,1,1]},"o":{"x":[0.02,0.02,0.333],"y":[1.991,1.991,0]},"t":3,"s":[0,0,100]},{"t":48.0000019550801,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-51,-3],[0,0]],"o":[[0,0],[51,3],[0,0]],"v":[[-54,-57.5],[3,-2.5],[39,57.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.579999976065,0.859000052658,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[71.5,75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"R_네모 블루","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[648.11,211.289,0],"ix":2},"a":{"a":0,"k":[18.822,20.282,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.469,0.469,0.667],"y":[1,1,1]},"o":{"x":[0.02,0.02,0.333],"y":[1.991,1.991,0]},"t":0,"s":[0,0,100]},{"t":45.0000018328876,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.667,-0.351],[0,0],[-0.587,-0.759],[0,0],[-0.639,0.73],[0,0],[0.443,0.583],[0,0]],"o":[[0,0],[-0.848,0.446],[0,0],[0.594,0.768],[0,0],[0.483,-0.551],[0,0],[-0.456,-0.6]],"v":[[-1.266,-19.681],[-17.484,-11.145],[-17.985,-8.835],[3.744,19.229],[6.124,19.302],[18.061,5.659],[18.129,3.709],[0.68,-19.249]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.74900004069,0.791999966491,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[18.822,20.282],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"R_직선 초록","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":21.354,"ix":10},"p":{"a":0,"k":[639,98.396,0],"ix":2},"a":{"a":0,"k":[98.25,32.561,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.469,0.469,0.667],"y":[1,1,1]},"o":{"x":[0.02,0.02,0.333],"y":[1.991,1.991,0]},"t":0,"s":[0,0,100]},{"t":45.0000018328876,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.377],[0,0],[-0.52,0.13],[-50.335,-23.243],[0,0.6],[0,0],[0.252,0.148],[61.187,-15.753]],"o":[[0,0],[0,0.536],[7.822,-1.964],[0.545,0.252],[0,0],[0,-0.292],[-4.69,-2.737],[-0.365,0.095]],"v":[[-56,-3.754],[-56,9.539],[-54.983,10.339],[54.833,20.059],[56,19.319],[56,8.073],[55.597,7.364],[-55.376,-4.558]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.246999987434,1,0.776000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[56.25,20.561],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"R_직선 주황","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":33.443,"ix":10},"p":{"a":0,"k":[738.954,116.383,0],"ix":2},"a":{"a":0,"k":[98.204,33.6,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.469,0.469,0.667],"y":[1,1,1]},"o":{"x":[0.02,0.02,0.333],"y":[1.991,1.991,0]},"t":3,"s":[0,0,100]},{"t":48.0000019550801,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.516],[0,0],[-0.458,-0.04],[-35.646,-21.989],[-0.204,0.51],[0,0],[0.296,0.246],[74.082,5.655]],"o":[[0,0],[0,0.46],[7.551,0.654],[0.468,0.289],[0,0],[0.143,-0.358],[-3.949,-3.284],[-0.515,-0.039]],"v":[[-53.954,-19.426],[-53.954,-9.199],[-53.152,-8.317],[49.156,20.061],[50.437,19.64],[53.811,11.204],[53.559,10.197],[-52.993,-20.311]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.666999966491,0.224000010771,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[54.204,20.6],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0}],"markers":[]}
--------------------------------------------------------------------------------
/assets/loading.json:
--------------------------------------------------------------------------------
1 | {"v":"5.7.1","fr":30,"ip":0,"op":110,"w":108,"h":108,"nm":"匹配","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":15,"s":[80]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":40,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[70]},{"t":75,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[54,54,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":15,"s":[80,80,100]},{"t":40,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[12,12],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.129411771894,0.501960813999,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":110,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":10,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":40,"s":[70]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":45,"s":[20]},{"t":50,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[54,54,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":10,"s":[80,80,100]},{"t":50,"s":[300,300,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[12,12],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.701960784314,0.827450980392,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":110,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"3","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":45,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":75,"s":[70]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":80,"s":[20]},{"t":85,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[54,54,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":45,"s":[80,80,100]},{"t":85,"s":[300,300,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[12,12],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.701960784314,0.827450980392,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"3","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":110,"st":0,"bm":0}],"markers":[]}
--------------------------------------------------------------------------------
/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/assets/logo.png
--------------------------------------------------------------------------------
/assets/profile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/assets/profile.png
--------------------------------------------------------------------------------
/assets/profile_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/assets/profile_default.png
--------------------------------------------------------------------------------
/assets/shape.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/assets/shape.png
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | 9.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/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.
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | group_chat_room_responsive
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 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/lib/data/datasource/firebase_remote_datasource.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 | import 'package:firebase_auth/firebase_auth.dart';
3 | import 'package:group_chat_room_responsive/data/model/text_message_model.dart';
4 | import 'package:group_chat_room_responsive/data/model/user_model.dart';
5 | import 'package:group_chat_room_responsive/domain/entities/text_message_entity.dart';
6 |
7 | abstract class FirebaseRemoteDataSource {
8 | Future signUp(String email, String password);
9 |
10 | Future signIn(String email, String password);
11 |
12 | Future signOut();
13 |
14 | Future isSignIn();
15 |
16 | Future getCurrentUid();
17 |
18 | Future getCreateCurrentUser(
19 | String email, String name, String profileUrl);
20 |
21 | Future sendTextMessage(TextMessageEntity textMessage);
22 |
23 | Stream> getUsers();
24 |
25 | Stream> getMessages();
26 | }
27 |
28 | class FirebaseRemoteDataSourceImpl implements FirebaseRemoteDataSource {
29 | final FirebaseAuth _auth = FirebaseAuth.instance;
30 | final _userCollection = FirebaseFirestore.instance.collection("users");
31 | final _globalChatChannelCollection =
32 | FirebaseFirestore.instance.collection("globalChatChannel");
33 |
34 | final String channelId = "8ghYhb9YN58qQeSBy2MG";
35 |
36 | @override
37 | Future getCurrentUid() async => _auth.currentUser.uid;
38 |
39 | @override
40 | Future isSignIn() async => _auth.currentUser.uid != null;
41 |
42 | @override
43 | Future signIn(String email, String password) async {
44 | await _auth.signInWithEmailAndPassword(email: email, password: password);
45 | }
46 |
47 | @override
48 | Future signUp(String email, String password) async {
49 | await _auth.createUserWithEmailAndPassword(
50 | email: email, password: password);
51 | }
52 |
53 | @override
54 | Future getCreateCurrentUser(
55 | String email, String name, String profileUrl) async {
56 | _userCollection.doc(_auth.currentUser.uid).get().then((user) {
57 | if (!user.exists) {
58 | final newUser = UserModel(
59 | name: name,
60 | email: email,
61 | uid: _auth.currentUser.uid,
62 | profileUrl: profileUrl,
63 | ).toDocument();
64 | _userCollection.doc(_auth.currentUser.uid).set(newUser);
65 | return;
66 | } else {
67 | print("User Already exists");
68 | return;
69 | }
70 | });
71 | }
72 |
73 | @override
74 | Stream> getMessages() {
75 | return _globalChatChannelCollection
76 | .doc(channelId)
77 | .collection("messages")
78 | .orderBy("time")
79 | .snapshots()
80 | .map((querySnapshot) => querySnapshot.docs
81 | .map((docSnapshot) => TextMessageModel.fromSnapshot(docSnapshot))
82 | .toList());
83 | }
84 |
85 | @override
86 | Stream> getUsers() {
87 | return _userCollection.snapshots().map(
88 | (querySnapShot) => querySnapShot.docs
89 | .map((docSnapshot) => UserModel.fromSnapshot(docSnapshot))
90 | .toList(),
91 | );
92 | }
93 |
94 | @override
95 | Future sendTextMessage(TextMessageEntity textMessage) async {
96 | final newMessage = TextMessageModel(
97 | message: textMessage.message,
98 | recipientId: textMessage.recipientId,
99 | time: textMessage.time,
100 | receiverName: textMessage.receiverName,
101 | senderId: textMessage.senderId,
102 | senderName: textMessage.senderName,
103 | type: textMessage.type,
104 | );
105 | _globalChatChannelCollection
106 | .doc(channelId)
107 | .collection("messages")
108 | .add(newMessage.toDocument());
109 | }
110 |
111 | @override
112 | Future signOut() async{
113 | await _auth.signOut();
114 | }
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/lib/data/model/text_message_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 | import 'package:cloud_firestore_platform_interface/src/timestamp.dart';
3 | import 'package:flutter/foundation.dart';
4 | import 'package:group_chat_room_responsive/domain/entities/text_message_entity.dart';
5 |
6 | class TextMessageModel extends TextMessageEntity {
7 | TextMessageModel({String recipientId, String senderId, String senderName,
8 | String type="TEXT", Timestamp time, String message, String receiverName})
9 | : super(recipientId, senderId, senderName, type, time, message, receiverName);
10 |
11 | factory TextMessageModel.fromJson(Map json){
12 | return TextMessageModel(
13 | recipientId: json['recipientId'],
14 | message:json['message'],
15 | time: json['time'],
16 | receiverName:json['receiverName'],
17 | senderId:json['senderId'],
18 | senderName:json['senderName'],
19 | type:json['type'],
20 | );
21 | }
22 |
23 | factory TextMessageModel.fromSnapshot(DocumentSnapshot documentSnapshot){
24 | return TextMessageModel(
25 | time: documentSnapshot.data()['time'],
26 | message:documentSnapshot.data()['message'],
27 | receiverName: documentSnapshot.data()['receiverName'],
28 | recipientId: documentSnapshot.data()['recipientId'],
29 | senderId:documentSnapshot.data()['senderId'],
30 | senderName:documentSnapshot.data()['senderName'],
31 | type:documentSnapshot.data()['type'],
32 | );
33 | }
34 |
35 | Map toDocument(){
36 | return {
37 | "recipientId":recipientId,
38 | "senderId":senderId,
39 | "senderName":senderName,
40 | "type":type,
41 | "time":time,
42 | "message":message,
43 | "receiverName":receiverName
44 | };
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/data/model/user_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 | import 'package:group_chat_room_responsive/domain/entities/user_entity.dart';
3 |
4 | class UserModel extends UserEntity {
5 | UserModel({String name, String email, String uid, String profileUrl})
6 | : super(name, email, uid, profileUrl);
7 |
8 | factory UserModel.fromJson(Map json){
9 | return UserModel(
10 | name: json['name'],
11 | profileUrl: json['profileUrl'],
12 | email: json['email'],
13 | uid: json['uid']
14 | );
15 | }
16 | factory UserModel.fromSnapshot(DocumentSnapshot documentSnapshot){
17 | return UserModel(
18 | name: documentSnapshot.data()['name'],
19 | uid: documentSnapshot.data()['uid'],
20 | email: documentSnapshot.data()['email'],
21 | profileUrl: documentSnapshot.data()['profileUrl'],
22 | );
23 | }
24 | Map toDocument(){
25 | return {
26 | "name" :name,
27 | "uid" :uid,
28 | "email":email,
29 | "profileUrl":profileUrl,
30 | };
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/data/repositories/firebasee_repository_impl.dart:
--------------------------------------------------------------------------------
1 | import 'package:group_chat_room_responsive/data/datasource/firebase_remote_datasource.dart';
2 | import 'package:group_chat_room_responsive/domain/entities/text_message_entity.dart';
3 | import 'package:group_chat_room_responsive/domain/entities/user_entity.dart';
4 | import 'package:group_chat_room_responsive/domain/repositories/firebase_repository.dart';
5 |
6 | class FireBaseRepositoryImpl implements FireBaseRepository {
7 | final FirebaseRemoteDataSource firebaseRemoteDataSource;
8 |
9 | FireBaseRepositoryImpl({this.firebaseRemoteDataSource});
10 |
11 | @override
12 | Future getCurrentUid() async =>
13 | await firebaseRemoteDataSource.getCurrentUid();
14 |
15 | @override
16 | Future isSignIn() async =>
17 | await firebaseRemoteDataSource.isSignIn();
18 |
19 | @override
20 | Future signIn(String email, String password) async =>
21 | await firebaseRemoteDataSource.signIn(email, password);
22 |
23 | @override
24 | Future signUp(String email, String password) async =>
25 | await firebaseRemoteDataSource.signUp(email, password);
26 |
27 | @override
28 | Future getCreateCurrentUser(String email, String name,
29 | String profileUrl)async {
30 | return await firebaseRemoteDataSource.getCreateCurrentUser(email, name, profileUrl);
31 | }
32 |
33 | @override
34 | Stream> getMessages() {
35 | return firebaseRemoteDataSource.getMessages();
36 | }
37 |
38 | @override
39 | Stream> getUsers() {
40 | return firebaseRemoteDataSource.getUsers();
41 | }
42 |
43 | @override
44 | Future sendTextMessage(TextMessageEntity textMessage) {
45 | return firebaseRemoteDataSource.sendTextMessage(textMessage);
46 | }
47 |
48 | @override
49 | Future signOut() => firebaseRemoteDataSource.signOut();
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/lib/domain/entities/text_message_entity.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 | import 'package:cloud_firestore/cloud_firestore.dart';
4 | import 'package:equatable/equatable.dart';
5 |
6 | class TextMessageEntity extends Equatable{
7 | final String recipientId;
8 | final String senderId;
9 | final String senderName;
10 | final String type;
11 | final Timestamp time;
12 | final String message;
13 | final String receiverName;
14 |
15 | TextMessageEntity(this.recipientId, this.senderId, this.senderName, this.type, this.time, this.message, this.receiverName);
16 |
17 | @override
18 | // TODO: implement props
19 | List get props => [recipientId, senderId, senderName, type, time, message, receiverName];
20 |
21 | }
--------------------------------------------------------------------------------
/lib/domain/entities/user_entity.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:equatable/equatable.dart';
3 |
4 | class UserEntity extends Equatable{
5 | final String name;
6 | final String email;
7 | final String uid;
8 | final String profileUrl;
9 |
10 | UserEntity(this.name, this.email, this.uid, this.profileUrl);
11 |
12 | @override
13 | // TODO: implement props
14 | List get props => [name,email,uid,profileUrl];
15 | }
--------------------------------------------------------------------------------
/lib/domain/repositories/firebase_repository.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 | import 'package:group_chat_room_responsive/domain/entities/text_message_entity.dart';
4 | import 'package:group_chat_room_responsive/domain/entities/user_entity.dart';
5 |
6 | abstract class FireBaseRepository{
7 | Future signUp(String email,String password);
8 | Future signIn(String email,String password);
9 | Future isSignIn();
10 | Future signOut();
11 | Future getCurrentUid();
12 | Future getCreateCurrentUser(
13 | String email, String name, String profileUrl);
14 | Future sendTextMessage(TextMessageEntity textMessage);
15 | Stream> getUsers();
16 | Stream> getMessages();
17 | }
--------------------------------------------------------------------------------
/lib/domain/usecase/get_create_current_user.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 | import 'package:group_chat_room_responsive/domain/repositories/firebase_repository.dart';
4 |
5 | class GetCreateCurrentUser{
6 | final FireBaseRepository fireBaseRepository;
7 |
8 | GetCreateCurrentUser({this.fireBaseRepository});
9 |
10 | Future call(String email,String name,String profileUrl)async{
11 | fireBaseRepository.getCreateCurrentUser(email, name, profileUrl);
12 | }
13 |
14 | }
--------------------------------------------------------------------------------
/lib/domain/usecase/get_current_uid.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 | import 'package:group_chat_room_responsive/domain/repositories/firebase_repository.dart';
4 |
5 | class GetCurrentUid{
6 | final FireBaseRepository repository;
7 |
8 | GetCurrentUid({this.repository});
9 |
10 | Future call() async => await repository.getCurrentUid();
11 |
12 | }
--------------------------------------------------------------------------------
/lib/domain/usecase/get_messages_usecase.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 | import 'package:group_chat_room_responsive/domain/entities/text_message_entity.dart';
4 | import 'package:group_chat_room_responsive/domain/repositories/firebase_repository.dart';
5 |
6 | class GetMessagesUseCase {
7 | final FireBaseRepository repository;
8 |
9 | GetMessagesUseCase({this.repository});
10 |
11 | Stream> call() => repository.getMessages();
12 |
13 | }
--------------------------------------------------------------------------------
/lib/domain/usecase/get_useres_usecase.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 | import 'package:group_chat_room_responsive/domain/entities/user_entity.dart';
4 | import 'package:group_chat_room_responsive/domain/repositories/firebase_repository.dart';
5 |
6 | class GetUsersUseCase {
7 | final FireBaseRepository repository;
8 |
9 | GetUsersUseCase({this.repository});
10 |
11 | Stream> call() => repository.getUsers();
12 |
13 |
14 | }
--------------------------------------------------------------------------------
/lib/domain/usecase/is_signin_usecase.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:group_chat_room_responsive/domain/repositories/firebase_repository.dart';
3 |
4 | class IsSignInUseCase{
5 | final FireBaseRepository repository;
6 |
7 | IsSignInUseCase(this.repository);
8 |
9 | Future call() async => repository.isSignIn();
10 | }
--------------------------------------------------------------------------------
/lib/domain/usecase/send_text_message_usecase.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 | import 'package:group_chat_room_responsive/domain/entities/text_message_entity.dart';
4 | import 'package:group_chat_room_responsive/domain/repositories/firebase_repository.dart';
5 |
6 | class SendTextMessageUseCase{
7 | final FireBaseRepository repository;
8 |
9 | SendTextMessageUseCase({this.repository});
10 |
11 | Future call(TextMessageEntity textMessage){
12 | return repository.sendTextMessage(textMessage);
13 | }
14 |
15 | }
--------------------------------------------------------------------------------
/lib/domain/usecase/sign_out_usecase.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | import 'package:group_chat_room_responsive/domain/repositories/firebase_repository.dart';
5 |
6 | class SignOutUseCase{
7 | final FireBaseRepository repository;
8 |
9 | SignOutUseCase({this.repository});
10 |
11 | Future call()async{
12 | return await repository.signOut();
13 | }
14 |
15 | }
--------------------------------------------------------------------------------
/lib/domain/usecase/signin_usecase.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 | import 'package:group_chat_room_responsive/domain/repositories/firebase_repository.dart';
4 |
5 | class SignInUseCase{
6 | final FireBaseRepository repository;
7 |
8 | SignInUseCase({this.repository});
9 |
10 | Future call(String email,String password){
11 | return repository.signIn(email, password);
12 | }
13 |
14 | }
--------------------------------------------------------------------------------
/lib/domain/usecase/signup_usecase.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 | import 'package:group_chat_room_responsive/domain/repositories/firebase_repository.dart';
4 |
5 | class SignUpUseCase{
6 | final FireBaseRepository repository;
7 |
8 | SignUpUseCase({this.repository});
9 |
10 | Future call(String email,String password) async{
11 | return repository.signUp(email, password);
12 | }
13 | }
--------------------------------------------------------------------------------
/lib/injection_container.dart:
--------------------------------------------------------------------------------
1 | import 'package:get_it/get_it.dart';
2 | import 'package:group_chat_room_responsive/data/datasource/firebase_remote_datasource.dart';
3 | import 'package:group_chat_room_responsive/data/repositories/firebasee_repository_impl.dart';
4 | import 'package:group_chat_room_responsive/domain/repositories/firebase_repository.dart';
5 | import 'package:group_chat_room_responsive/domain/usecase/get_create_current_user.dart';
6 | import 'package:group_chat_room_responsive/domain/usecase/get_current_uid.dart';
7 | import 'package:group_chat_room_responsive/domain/usecase/get_messages_usecase.dart';
8 | import 'package:group_chat_room_responsive/domain/usecase/get_useres_usecase.dart';
9 | import 'package:group_chat_room_responsive/domain/usecase/is_signin_usecase.dart';
10 | import 'package:group_chat_room_responsive/domain/usecase/send_text_message_usecase.dart';
11 | import 'package:group_chat_room_responsive/domain/usecase/sign_out_usecase.dart';
12 | import 'package:group_chat_room_responsive/domain/usecase/sign_out_usecase.dart';
13 | import 'package:group_chat_room_responsive/domain/usecase/signin_usecase.dart';
14 | import 'package:group_chat_room_responsive/presentation/bloc/auth/auth_cubit.dart';
15 | import 'package:group_chat_room_responsive/presentation/bloc/communication/communication_cubit.dart';
16 | import 'package:group_chat_room_responsive/presentation/bloc/login/login_cubit.dart';
17 |
18 | import 'domain/usecase/signup_usecase.dart';
19 | import 'presentation/bloc/user/user_cubit.dart';
20 |
21 | final sl = GetIt.instance;
22 |
23 | Future init() async {
24 | //Features bloc,
25 | sl.registerFactory(() =>
26 | AuthCubit(isSignInUseCase: sl.call(), getCurrentUidUseCase: sl.call()));
27 | sl.registerFactory(() => LoginCubit(
28 | signInUseCase: sl.call(),
29 | signUpUseCase: sl.call(),
30 | getCreateCurrentUser: sl.call(),
31 | signOutUseCase: sl.call(),
32 | ));
33 | sl.registerFactory(() => UserCubit(usersUseCase: sl.call()));
34 | sl.registerFactory(() => CommunicationCubit(
35 | getMessagesUseCase: sl.call(), sendTextMessageUseCase: sl.call()));
36 | //!useCase
37 | sl.registerLazySingleton(() => IsSignInUseCase(sl.call()));
38 | sl.registerLazySingleton(
39 | () => GetCurrentUid(repository: sl.call()));
40 | sl.registerLazySingleton(
41 | () => GetCreateCurrentUser(fireBaseRepository: sl.call()));
42 | sl.registerLazySingleton(
43 | () => SignInUseCase(repository: sl.call()));
44 | sl.registerLazySingleton(
45 | () => SignUpUseCase(repository: sl.call()));
46 | sl.registerLazySingleton(
47 | () => GetUsersUseCase(repository: sl.call()));
48 | sl.registerLazySingleton(
49 | () => GetMessagesUseCase(repository: sl.call()));
50 | sl.registerLazySingleton(
51 | () => SendTextMessageUseCase(repository: sl.call()));
52 | sl.registerLazySingleton(
53 | () => SignOutUseCase(repository: sl.call()));
54 |
55 | //repository
56 | sl.registerLazySingleton(
57 | () => FireBaseRepositoryImpl(firebaseRemoteDataSource: sl.call()));
58 | //dataSource
59 | sl.registerLazySingleton(
60 | () => FirebaseRemoteDataSourceImpl());
61 | //external
62 | //e.g final sharedPreference=await SharedPreferences.getInstance();
63 | }
64 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_bloc/flutter_bloc.dart';
3 | import 'package:group_chat_room_responsive/presentation/bloc/auth/auth_cubit.dart';
4 |
5 | import 'presentation/bloc/communication/communication_cubit.dart';
6 | import 'presentation/bloc/login/login_cubit.dart';
7 | import 'presentation/bloc/user/user_cubit.dart';
8 | import 'presentation/screens/home_screen.dart';
9 | import 'injection_container.dart' as di;
10 | import 'presentation/screens/welcome_screen.dart';
11 | import 'package:firebase_core/firebase_core.dart';
12 |
13 |
14 |
15 | void main() async{
16 | WidgetsFlutterBinding.ensureInitialized();
17 | await Firebase.initializeApp();
18 | await di.init();
19 | runApp(MyApp());
20 | }
21 |
22 | class MyApp extends StatelessWidget {
23 | @override
24 | Widget build(BuildContext context) {
25 |
26 |
27 | return MultiBlocProvider(
28 | providers: [
29 | BlocProvider(
30 | create: (_) => di.sl()..appStarted(),
31 | ),
32 | BlocProvider(
33 | create: (_) => di.sl(),
34 | ),
35 | BlocProvider(
36 | create: (_) => di.sl(),
37 | ),
38 | BlocProvider(
39 | create: (_) => di.sl(),
40 | )
41 | ],
42 | child: MaterialApp(
43 | title: 'Flutter Group Chat Room Responsive',
44 | debugShowCheckedModeBanner: false,
45 | routes: {
46 | "/" : (context){
47 | return BlocBuilder(
48 | builder: (context,authState){
49 | if (authState is Authenticated){
50 | return WelcomeScreen(uid:authState.uid);
51 | }
52 | if (authState is UnAuthenticated){
53 | return HomeScreen();
54 | }
55 | return Container();
56 | },
57 | );
58 | }
59 | },
60 | ),
61 | );
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/lib/presentation/bloc/auth/auth_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:equatable/equatable.dart';
3 | import 'package:group_chat_room_responsive/domain/usecase/get_current_uid.dart';
4 | import 'package:group_chat_room_responsive/domain/usecase/is_signin_usecase.dart';
5 |
6 | part 'auth_state.dart';
7 |
8 | class AuthCubit extends Cubit {
9 | final IsSignInUseCase isSignInUseCase;
10 | final GetCurrentUid getCurrentUidUseCase;
11 | AuthCubit({this.isSignInUseCase,this.getCurrentUidUseCase}) : super(AuthInitial());
12 |
13 |
14 | Future appStarted()async{
15 |
16 | try{
17 | final isSignIn=await isSignInUseCase.call();
18 | print("Sign $isSignIn");
19 | if (isSignIn==true){
20 | final currentUid=await getCurrentUidUseCase.call();
21 | emit(Authenticated(uid: currentUid));
22 | }else{
23 | emit(UnAuthenticated());
24 | }
25 | }catch(_){
26 | print("heelo appStarted catch");
27 | emit(UnAuthenticated());
28 | }
29 | }
30 | Future loggedIn() async{
31 | final currentUid=await getCurrentUidUseCase.call();
32 | emit(Authenticated(uid: currentUid));
33 | }
34 | Future loggedOut() async {
35 | emit(UnAuthenticated());
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/presentation/bloc/auth/auth_state.dart:
--------------------------------------------------------------------------------
1 | part of 'auth_cubit.dart';
2 |
3 | abstract class AuthState extends Equatable {
4 | const AuthState();
5 | }
6 |
7 | class AuthInitial extends AuthState {
8 | @override
9 | List get props => [];
10 | }
11 | class Authenticated extends AuthState{
12 | final String uid;
13 |
14 | Authenticated({this.uid});
15 | @override
16 | // TODO: implement props
17 | List get props => [uid];
18 | }
19 | class UnAuthenticated extends AuthState{
20 |
21 |
22 | @override
23 | // TODO: implement props
24 | List get props => [];
25 | }
26 |
--------------------------------------------------------------------------------
/lib/presentation/bloc/communication/communication_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:bloc/bloc.dart';
4 | import 'package:cloud_firestore/cloud_firestore.dart';
5 | import 'package:equatable/equatable.dart';
6 | import 'package:group_chat_room_responsive/domain/entities/text_message_entity.dart';
7 | import 'package:group_chat_room_responsive/domain/usecase/get_messages_usecase.dart';
8 | import 'package:group_chat_room_responsive/domain/usecase/send_text_message_usecase.dart';
9 |
10 | part 'communication_state.dart';
11 |
12 | class CommunicationCubit extends Cubit {
13 | final GetMessagesUseCase getMessagesUseCase;
14 | final SendTextMessageUseCase sendTextMessageUseCase;
15 | CommunicationCubit({this.getMessagesUseCase,this.sendTextMessageUseCase}) : super(CommunicationInitial());
16 |
17 | Future sendTextMsg({String name,String uid,String message})async{
18 | try{
19 | await sendTextMessageUseCase.call(TextMessageEntity("", uid, name, "TEXT", Timestamp.now(), message, ""));
20 | }on SocketException catch(_){}
21 | }
22 | Future getTextMessages()async{
23 | try{
24 | final messages=getMessagesUseCase.call();
25 | messages.listen((msg) {
26 | emit(CommunicationLoaded(messages: msg));
27 | });
28 | }on SocketException catch(_){}
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/presentation/bloc/communication/communication_state.dart:
--------------------------------------------------------------------------------
1 | part of 'communication_cubit.dart';
2 |
3 | abstract class CommunicationState extends Equatable {
4 | const CommunicationState();
5 | }
6 |
7 | class CommunicationInitial extends CommunicationState {
8 | @override
9 | List get props => [];
10 | }
11 |
12 | class CommunicationLoading extends CommunicationState{
13 | @override
14 | // TODO: implement props
15 | List get props => [];
16 |
17 | }
18 |
19 | class CommunicationLoaded extends CommunicationState{
20 | final List messages;
21 |
22 | CommunicationLoaded({this.messages});
23 | @override
24 | // TODO: implement props
25 | List get props => [messages];
26 | }
--------------------------------------------------------------------------------
/lib/presentation/bloc/login/login_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:equatable/equatable.dart';
3 | import 'package:group_chat_room_responsive/domain/usecase/get_create_current_user.dart';
4 | import 'package:group_chat_room_responsive/domain/usecase/sign_out_usecase.dart';
5 | import 'package:group_chat_room_responsive/domain/usecase/signin_usecase.dart';
6 | import 'package:group_chat_room_responsive/domain/usecase/signup_usecase.dart';
7 | import 'dart:io';
8 |
9 | part 'login_state.dart';
10 |
11 | class LoginCubit extends Cubit {
12 | final SignUpUseCase signUpUseCase;
13 | final SignInUseCase signInUseCase;
14 | final GetCreateCurrentUser getCreateCurrentUser;
15 | final SignOutUseCase signOutUseCase;
16 | LoginCubit({this.signInUseCase,this.signUpUseCase,this.getCreateCurrentUser,this.signOutUseCase}) : super(LoginInitial());
17 |
18 | Future submitLogin({String email,String password})async{
19 | emit(LoginLoading());
20 | try{
21 | await signInUseCase.call(email, password);
22 | emit(LoginSuccess());
23 | }on SocketException catch(e){
24 | emit(LoginFailure(e.message));
25 | }catch(_){
26 | emit(LoginFailure("firebase exception"));
27 | }
28 | }
29 | Future submitRegistration({String email,String password,String name})async{
30 | emit(LoginLoading());
31 | try{
32 | await signUpUseCase.call(email, password);
33 | await getCreateCurrentUser.call(email, name, "");
34 | emit(LoginSuccess());
35 | }on SocketException catch(e){
36 | emit(LoginFailure(e.message));
37 | }catch(_){
38 | emit(LoginFailure("firebase exception"));
39 | }
40 | }
41 | Future submitSignOut()async{
42 | try{
43 | await signOutUseCase.call();
44 | }on SocketException catch(_){}
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/presentation/bloc/login/login_state.dart:
--------------------------------------------------------------------------------
1 | part of 'login_cubit.dart';
2 |
3 | abstract class LoginState extends Equatable {
4 | const LoginState();
5 | }
6 |
7 | class LoginInitial extends LoginState {
8 | @override
9 | List get props => [];
10 | }
11 |
12 | class LoginLoading extends LoginState{
13 | @override
14 | // TODO: implement props
15 | List get props => [];
16 |
17 | }
18 | class LoginFailure extends LoginState{
19 | final String errorMessage;
20 |
21 | LoginFailure(this.errorMessage);
22 | @override
23 | // TODO: implement props
24 | List get props => [this.errorMessage];
25 |
26 | }
27 | class LoginSuccess extends LoginState{
28 | @override
29 | // TODO: implement props
30 | List get props => [];
31 | }
--------------------------------------------------------------------------------
/lib/presentation/bloc/user/user_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:bloc/bloc.dart';
4 | import 'package:equatable/equatable.dart';
5 | import 'package:group_chat_room_responsive/domain/entities/user_entity.dart';
6 | import 'package:group_chat_room_responsive/domain/usecase/get_useres_usecase.dart';
7 |
8 | part 'user_state.dart';
9 |
10 | class UserCubit extends Cubit {
11 | final GetUsersUseCase usersUseCase;
12 | UserCubit({this.usersUseCase}) : super(UserInitial());
13 |
14 | Future getUsers()async{
15 | try{
16 | final user=usersUseCase.call();
17 | user.listen((users) {
18 | emit(UserLoaded(users: users));
19 | });
20 | }on SocketException catch(_){}
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/presentation/bloc/user/user_state.dart:
--------------------------------------------------------------------------------
1 | part of 'user_cubit.dart';
2 |
3 | abstract class UserState extends Equatable {
4 | const UserState();
5 | }
6 |
7 | class UserInitial extends UserState {
8 | @override
9 | List get props => [];
10 | }
11 | class UserLoaded extends UserState{
12 | final List users;
13 |
14 | UserLoaded({this.users});
15 | @override
16 | // TODO: implement props
17 | List get props => [users];
18 | }
19 | class UserLoading extends UserState{
20 | @override
21 | // TODO: implement props
22 | List get props => throw UnimplementedError();
23 | }
24 |
--------------------------------------------------------------------------------
/lib/presentation/pages/mobile/mobile_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:group_chat_room_responsive/presentation/pages/mobile/widget/body_widget.dart';
3 | import 'package:responsive_builder/responsive_builder.dart';
4 |
5 | class MobilePage extends StatelessWidget {
6 | @override
7 | Widget build(BuildContext context) {
8 | return ResponsiveBuilder(
9 | builder: (context,sizingInformation){
10 | return Scaffold(
11 | body: Container(
12 | child: BodyWidgetMobile(sizingInformation: sizingInformation,),
13 | ),
14 | );
15 | },
16 | );
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/presentation/pages/mobile/single_chat_page_mobile.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:bubble/bubble.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_bloc/flutter_bloc.dart';
6 | import 'package:group_chat_room_responsive/presentation/bloc/communication/communication_cubit.dart';
7 | import 'package:group_chat_room_responsive/presentation/pages/mobile/widget/mobile_message_layout.dart';
8 | import 'package:group_chat_room_responsive/presentation/pages/widget/message_layout.dart';
9 | import 'package:intl/intl.dart';
10 | import 'package:responsive_builder/responsive_builder.dart';
11 |
12 | class SingleChatPageMobile extends StatefulWidget {
13 | final String uid;
14 | final String userName;
15 |
16 | const SingleChatPageMobile({Key key, this.uid, this.userName}) : super(key: key);
17 |
18 | @override
19 | _SingleChatPageMobileState createState() => _SingleChatPageMobileState();
20 | }
21 |
22 | class _SingleChatPageMobileState extends State {
23 | TextEditingController _messageController = TextEditingController();
24 | ScrollController _scrollController=ScrollController();
25 | @override
26 | void initState() {
27 | BlocProvider.of(context).getTextMessages();
28 | super.initState();
29 | }
30 |
31 | @override
32 | Widget build(BuildContext context) {
33 | return BlocBuilder(
34 | builder: (context,state){
35 | if (state is CommunicationLoaded){
36 | return _bodyWidget(state);
37 | }
38 | return _loadingWidget();
39 | },
40 | );
41 | }
42 | Widget _bodyWidget(CommunicationLoaded messages) {
43 | return Scaffold(
44 | body: Stack(
45 | children: [
46 | Positioned.fill(
47 | child: Image.asset(
48 | "assets/background_img.png",
49 | fit: BoxFit.cover,
50 | ),
51 | ),
52 | Column(
53 | children: [
54 | _headerWidget(),
55 | _listMessagesWidget(messages),
56 | _sendTextMessageWidget(),
57 | ],
58 | ),
59 | ],
60 | ),
61 | );
62 | }
63 | Widget _loadingWidget(){
64 | return Scaffold(
65 | body: Stack(
66 | children: [
67 | Positioned.fill(
68 | child: Image.asset(
69 | "assets/background_img.png",
70 | fit: BoxFit.cover,
71 | ),
72 | ),
73 | Column(
74 | children: [
75 | _headerWidget(),
76 | Expanded(child: Center(child: CircularProgressIndicator(),)),
77 | _sendTextMessageWidget(),
78 | ],
79 | ),
80 | ],
81 | ),
82 | );
83 | }
84 | Widget _headerWidget() {
85 | return Container(
86 | padding: EdgeInsets.only(left: 15,right: 15,top: 20),
87 | height: 70,
88 | width: double.infinity,
89 | decoration: BoxDecoration(
90 | gradient: LinearGradient(
91 | colors: [
92 | Colors.indigo[400],
93 | Colors.blue[300],
94 | ],
95 | )),
96 | child: Row(
97 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
98 | children: [
99 | Row(
100 | children: [
101 | Container(
102 | width: 40, height: 40, child: Image.asset("assets/logo.png")),
103 | Text(
104 | "Global Chat Room",
105 | style: TextStyle(
106 | fontSize: 18,
107 | color: Colors.white,
108 | ),
109 | ),
110 | ],
111 | ),
112 | Text(
113 | "${widget.userName}",
114 | style: TextStyle(
115 | fontSize: 22,
116 | color: Colors.white,
117 | ),
118 | )
119 | ],
120 | ),
121 | );
122 | }
123 |
124 | Widget _listMessagesWidget(CommunicationLoaded messages) {
125 | Timer(
126 | Duration(milliseconds: 100),
127 | () => _scrollController
128 | .jumpTo(_scrollController.position.maxScrollExtent));
129 | return Expanded(
130 | child: Container(
131 | margin: EdgeInsets.symmetric(horizontal: 20),
132 | child: ListView.builder(
133 | controller: _scrollController,
134 | shrinkWrap: true,
135 | itemCount: messages.messages.length,
136 | itemBuilder: (_, index) {
137 | return messages.messages[index].senderId ==
138 | widget.uid
139 | ? MobileMessageLayout(
140 | type: messages.messages[index].type,
141 | senderId: messages.messages[index].senderId,
142 | senderName:
143 | messages.messages[index].senderName,
144 | text: messages.messages[index].message,
145 | time: DateFormat('hh:mm a').format(
146 | messages.messages[index].time.toDate()),
147 | color: Colors.green[300],
148 | align: TextAlign.left,
149 | nip: BubbleNip.rightTop,
150 | boxAlignment: CrossAxisAlignment.end,
151 | boxMainAxisAlignment: MainAxisAlignment.end,
152 | uid: widget.uid,)
153 | : MobileMessageLayout(
154 | type: messages.messages[index].type,
155 | senderName:
156 | messages.messages[index].senderName,
157 | text: messages.messages[index].message,
158 | time: DateFormat('hh:mm a').format(
159 | messages.messages[index].time.toDate()),
160 | color: Colors.blue,
161 | align: TextAlign.left,
162 | nip: BubbleNip.leftTop,
163 | boxAlignment: CrossAxisAlignment.start,
164 | boxMainAxisAlignment: MainAxisAlignment.start,
165 | );
166 | },
167 | ),
168 | ),
169 | );
170 | }
171 |
172 | Widget _sendTextMessageWidget() {
173 | return Padding(
174 | padding: const EdgeInsets.only(bottom: 5),
175 | child: Container(
176 | padding: EdgeInsets.symmetric(horizontal: 20),
177 | height: 60,
178 | width: double.infinity,
179 | decoration: BoxDecoration(
180 | color: Colors.white,
181 | borderRadius: BorderRadius.all(Radius.circular(0.0)),
182 | border: Border.all(color: Colors.black.withOpacity(.4), width: 2)),
183 | child: Row(
184 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
185 | children: [
186 | Row(
187 | children: [
188 | _emojiWidget(),
189 | SizedBox(
190 | width: 8,
191 | ),
192 | _textFieldWidget(),
193 | ],
194 | ),
195 | Row(
196 | children: [
197 | _micWidget(),
198 | SizedBox(
199 | width: 8,
200 | ),
201 | _sendMessageButton(),
202 | ],
203 | )
204 | ],
205 | ),
206 | ),
207 | );
208 | }
209 |
210 | _emojiWidget() {
211 | return Container(
212 | height: 40,
213 | width: 40,
214 | decoration: BoxDecoration(
215 | color: Colors.black.withOpacity(.2),
216 | borderRadius: BorderRadius.all(Radius.circular(40))),
217 | child: Icon(
218 | Icons.emoji_symbols,
219 | color: Colors.white,
220 | ),
221 | );
222 | }
223 |
224 | _micWidget() {
225 | return Container(
226 | height: 40,
227 | width: 40,
228 | decoration: BoxDecoration(
229 | color: Colors.black.withOpacity(.2),
230 | borderRadius: BorderRadius.all(Radius.circular(40))),
231 | child: Icon(
232 | Icons.mic,
233 | color: Colors.white,
234 | ),
235 | );
236 | }
237 |
238 | _textFieldWidget() {
239 | return ResponsiveBuilder(
240 | builder: (_, sizingInformation) {
241 | return Container(
242 | width: sizingInformation.screenSize.width * 0.40,
243 | child: ConstrainedBox(
244 | constraints: BoxConstraints(
245 | maxHeight: 60,
246 | ),
247 | child: Scrollbar(
248 | child: TextField(
249 | controller: _messageController,
250 | maxLines: null,
251 | decoration: InputDecoration(
252 | border: InputBorder.none,
253 | hintText: "Type Feel Free <3 ..."),
254 | ),
255 | ),
256 | ),
257 | );
258 | },
259 | );
260 | }
261 |
262 | Widget _sendMessageButton() {
263 | return InkWell(
264 | onTap: () {
265 | if (_messageController.text.isNotEmpty) {
266 | _sendTextMessage();
267 | _messageController.clear();
268 | }
269 | },
270 | child: Container(
271 | height: 40,
272 | width: 40,
273 | decoration: BoxDecoration(
274 | color: Colors.green,
275 | borderRadius: BorderRadius.all(Radius.circular(40))),
276 | child: Icon(
277 | Icons.send,
278 | color: Colors.white,
279 | ),
280 | ),
281 | );
282 | }
283 |
284 | void _sendTextMessage() {
285 | BlocProvider.of(context).sendTextMsg(
286 | uid: widget.uid,
287 | name: widget.userName,
288 | message: _messageController.text);
289 | }
290 | }
291 |
--------------------------------------------------------------------------------
/lib/presentation/pages/mobile/welcome_page_mobile.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_bloc/flutter_bloc.dart';
4 | import 'package:group_chat_room_responsive/data/model/user_model.dart';
5 | import 'package:group_chat_room_responsive/presentation/bloc/auth/auth_cubit.dart';
6 | import 'package:group_chat_room_responsive/presentation/bloc/login/login_cubit.dart';
7 | import 'package:group_chat_room_responsive/presentation/bloc/user/user_cubit.dart';
8 | import 'package:group_chat_room_responsive/presentation/screens/single_chat_screen.dart';
9 | import 'package:lottie/lottie.dart';
10 |
11 | class WelcomePageMobile extends StatefulWidget {
12 | final String uid;
13 |
14 | const WelcomePageMobile({Key key, this.uid}) : super(key: key);
15 |
16 | @override
17 | _WelcomePageMobileState createState() => _WelcomePageMobileState();
18 | }
19 |
20 | class _WelcomePageMobileState extends State {
21 | @override
22 | void initState() {
23 | BlocProvider.of(context).getUsers();
24 | super.initState();
25 | }
26 |
27 | @override
28 | Widget build(BuildContext context) {
29 | return BlocBuilder(builder: (_, state) {
30 | if (state is UserLoaded) {
31 | return _bodyWidget(state);
32 | }
33 | return _loadingWidget();
34 | });
35 | }
36 |
37 | Widget _bodyWidget(UserLoaded users) {
38 | final user = users.users.firstWhere((user) => user.uid == widget.uid,
39 | orElse: () => UserModel());
40 | return Scaffold(
41 | body: Stack(
42 | children: [
43 | Container(
44 | decoration: BoxDecoration(
45 | gradient: LinearGradient(
46 | colors: [
47 | Colors.indigo[400],
48 | Colors.blue[300],
49 | ],
50 | )),
51 | ),
52 | Align(
53 | alignment: Alignment.topCenter,
54 | child: Lottie.asset("assets/congratulation.json"),
55 | ),
56 | Align(
57 | alignment: Alignment.bottomRight,
58 | child: Lottie.asset("assets/bubble.json"),
59 | ),
60 | Align(
61 | alignment: Alignment.topCenter,
62 | child: Container(
63 | margin: EdgeInsets.only(top: 80),
64 | child: Text(
65 | "Welcome ${user.name}",
66 | style: TextStyle(
67 | fontSize: 20,
68 | color: Colors.white,
69 | fontWeight: FontWeight.bold,
70 | ),
71 | )),
72 | ),
73 | _joinGlobalChatButton(user.name),
74 | _logOutWidget(),
75 | ],
76 | ),
77 | );
78 | }
79 |
80 | Widget _loadingWidget() {
81 | return Scaffold(
82 | body: Stack(
83 | children: [
84 | Container(
85 | decoration: BoxDecoration(
86 | gradient: LinearGradient(
87 | colors: [
88 | Colors.indigo[400],
89 | Colors.blue[300],
90 | ],
91 | )),
92 | ),
93 | Align(
94 | alignment: Alignment.center,
95 | child: CircularProgressIndicator(),
96 | ),
97 | ],
98 | ),
99 | );
100 | }
101 |
102 | Widget _joinGlobalChatButton(String name) {
103 | return Align(
104 | alignment: Alignment.center,
105 | child: Column(
106 | mainAxisAlignment: MainAxisAlignment.center,
107 | children: [
108 | Text(
109 | "Join Us For Fun",
110 | style: TextStyle(
111 | fontSize: 20,
112 | fontWeight: FontWeight.bold,
113 | ),
114 | ),
115 | SizedBox(
116 | height: 30,
117 | ),
118 | InkWell(
119 | onTap: (){
120 | Navigator.push(
121 | context,
122 | MaterialPageRoute(
123 | builder: (_) => SingleChatScreen(username: name,uid: widget.uid,),
124 | ),
125 | );
126 | },
127 | child: Container(
128 | width: 180,
129 | height: 60,
130 | alignment: Alignment.center,
131 | decoration: BoxDecoration(
132 | color: Colors.white.withOpacity(.3),
133 | borderRadius: BorderRadius.all(Radius.circular(20)),
134 | border: Border.all(color: Colors.white60, width: 2)),
135 | child: Text(
136 | "Join",
137 | style: TextStyle(fontSize: 20),
138 | ),
139 | ),
140 | ),
141 | ],
142 | ),
143 | );
144 | }
145 |
146 | Widget _logOutWidget() {
147 | return Align(
148 | alignment: Alignment.bottomLeft,
149 | child: InkWell(
150 | onTap: (){
151 | //TODO:Logout
152 | BlocProvider.of(context).loggedOut();
153 | BlocProvider.of(context).submitSignOut();
154 | },
155 | child: Container(
156 | margin: EdgeInsets.only(left: 15,bottom: 15),
157 | padding: EdgeInsets.all(10),
158 | decoration: BoxDecoration(
159 | color: Colors.white.withOpacity(.3),
160 | borderRadius: BorderRadius.circular(30),
161 | ),
162 | child: Icon(
163 | Icons.exit_to_app,
164 | size: 30,
165 | ),
166 | ),
167 | ),
168 | );
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/lib/presentation/pages/mobile/widget/body_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_bloc/flutter_bloc.dart';
4 | import 'package:group_chat_room_responsive/presentation/bloc/auth/auth_cubit.dart';
5 | import 'package:group_chat_room_responsive/presentation/bloc/login/login_cubit.dart';
6 | import 'package:lottie/lottie.dart';
7 | import 'package:responsive_builder/responsive_builder.dart';
8 |
9 | class BodyWidgetMobile extends StatefulWidget {
10 | final SizingInformation sizingInformation;
11 |
12 | const BodyWidgetMobile({Key key, this.sizingInformation}) : super(key: key);
13 |
14 | @override
15 | _BodyWidgetMobileState createState() => _BodyWidgetMobileState();
16 | }
17 |
18 | class _BodyWidgetMobileState extends State {
19 |
20 | TextEditingController _nameController;
21 | TextEditingController _emailController;
22 | TextEditingController _passwordController;
23 |
24 | bool isLoginPage=true;
25 |
26 | @override
27 | void initState() {
28 | _nameController=TextEditingController();
29 | _emailController=TextEditingController();
30 | _passwordController=TextEditingController();
31 | super.initState();
32 | }
33 | @override
34 | void dispose() {
35 | _nameController.dispose();
36 | _emailController.dispose();
37 | _passwordController.dispose();
38 | super.dispose();
39 | }
40 |
41 | @override
42 | Widget build(BuildContext context) {
43 | return BlocConsumer(
44 | builder: (context, state) {
45 | if (state is LoginLoading) {
46 | return _loadingWidget();
47 | }
48 | return _bodyWidget();
49 | },
50 | listener: (context, state) {
51 | if (state is LoginSuccess){
52 | BlocProvider.of(context).loggedIn();
53 | }
54 | },
55 | );
56 | }
57 | Widget _loadingWidget(){
58 | return SingleChildScrollView(
59 | child: Container(
60 | decoration: BoxDecoration(
61 | color: Colors.white,
62 | ),
63 | padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
64 | child: Column(
65 | mainAxisAlignment: MainAxisAlignment.center,
66 | children: [
67 | Text(
68 | "WELCOME TO eTechViral",
69 | style: TextStyle(
70 | fontSize: 30, color: Colors.black,fontWeight: FontWeight.bold),
71 | ),
72 | Text(
73 | "Flutter is changing the app development world. if you want to improve your flutter skill then join our channel because we try to upload one video per week. eTechViral :- flutter and dart app development tutorials crafted to make you win jobs.",
74 | textAlign: TextAlign.center,
75 | style: TextStyle(color: Colors.black54, fontSize: 16),
76 | ),
77 | SizedBox(
78 | height: 15,
79 | ),
80 | _imageWidget(),
81 | SizedBox(
82 | height: 15,
83 | ),
84 | _fromWidget(),
85 | SizedBox(
86 | height: 15,
87 | ),
88 | _buttonWidget(),
89 | SizedBox(
90 | height: 40,
91 | ),
92 | Align(
93 | alignment: Alignment.bottomCenter,
94 | child: Lottie.asset('assets/loading.json'),
95 | ),
96 | ],
97 | ),
98 | ),
99 | );
100 | }
101 | Widget _bodyWidget(){
102 | return SingleChildScrollView(
103 | child: Container(
104 | decoration: BoxDecoration(
105 | color: Colors.white,
106 | ),
107 | padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
108 | child: Column(
109 | mainAxisAlignment: MainAxisAlignment.center,
110 | children: [
111 | Text(
112 | "WELCOME TO eTechViral",
113 | style: TextStyle(
114 | fontSize: 30, color: Colors.black,fontWeight: FontWeight.bold),
115 | ),
116 | Text(
117 | "Flutter is changing the app development world. if you want to improve your flutter skill then join our channel because we try to upload one video per week. eTechViral :- flutter and dart app development tutorials crafted to make you win jobs.",
118 | textAlign: TextAlign.center,
119 | style: TextStyle(color: Colors.black54, fontSize: 16),
120 | ),
121 | SizedBox(
122 | height: 15,
123 | ),
124 | _imageWidget(),
125 | SizedBox(
126 | height: 15,
127 | ),
128 | _fromWidget(),
129 | SizedBox(
130 | height: 15,
131 | ),
132 | _buttonWidget(),
133 | SizedBox(
134 | height: 40,
135 | ),
136 | Align(
137 | alignment: Alignment.bottomCenter,
138 | child: _rowTextWidget(),
139 | ),
140 | ],
141 | ),
142 | ),
143 | );
144 | }
145 | Widget _imageWidget() {
146 | return Container(
147 | height: 60,
148 | width: 60,
149 | child: Image.asset("assets/profile.png"),
150 | );
151 | }
152 |
153 | Widget _fromWidget() {
154 | return Column(
155 | children: [
156 | isLoginPage==true?Text("",style: TextStyle(fontSize: 0),):Container(
157 | height: 60,
158 | alignment: Alignment.center,
159 | decoration: BoxDecoration(
160 | borderRadius: BorderRadius.all(Radius.circular(40)),
161 | border: Border.all(color: Colors.grey, width: 1.0),
162 | ),
163 | child: TextField(
164 | controller: _nameController,
165 | decoration: InputDecoration(
166 | border: InputBorder.none,
167 | hintText: "User Name",
168 | prefixIcon: Icon(Icons.person_outline),
169 | ),
170 | ),
171 | ),
172 | isLoginPage==true?Text("",style: TextStyle(fontSize: 0),):SizedBox(
173 | height: 20,
174 | ),
175 | Container(
176 | height: 60,
177 | alignment: Alignment.center,
178 | decoration: BoxDecoration(
179 | borderRadius: BorderRadius.all(Radius.circular(40)),
180 | border: Border.all(color: Colors.grey, width: 1.0),
181 | ),
182 | child: TextField(
183 | controller: _emailController,
184 | decoration: InputDecoration(
185 | border: InputBorder.none,
186 | hintText: "Email Address",
187 | prefixIcon: Icon(Icons.alternate_email),
188 | ),
189 | ),
190 | ),
191 | SizedBox(
192 | height: 20,
193 | ),
194 | Container(
195 | height: 60,
196 | alignment: Alignment.center,
197 | decoration: BoxDecoration(
198 | borderRadius: BorderRadius.all(Radius.circular(40)),
199 | border: Border.all(color: Colors.grey, width: 1.0),
200 | ),
201 | child: TextField(
202 | controller: _passwordController,
203 | obscureText: true,
204 | decoration: InputDecoration(
205 | border: InputBorder.none,
206 | hintText: "Password",
207 | prefixIcon: Icon(Icons.lock_outline),
208 | ),
209 | ),
210 | ),
211 | ],
212 | );
213 | }
214 |
215 | Widget _buttonWidget() {
216 | return InkWell(
217 | onTap: (){
218 | if (isLoginPage == true) {
219 | _submitLogin();
220 | } else {
221 | _submitRegistration();
222 | }
223 | },
224 | child: Container(
225 | margin: EdgeInsets.symmetric(horizontal: 10),
226 | width: widget.sizingInformation.screenSize.width,
227 | alignment: Alignment.center,
228 | padding: EdgeInsets.symmetric(vertical: 14),
229 | decoration: BoxDecoration(
230 | color: Colors.indigo,
231 | borderRadius: BorderRadius.all(Radius.circular(50)),
232 | ),
233 | child: Text(
234 | isLoginPage==true?"LOGIN":"REGISTER",
235 | style: TextStyle(fontSize: 18, color: Colors.white),
236 | ),
237 | ),
238 | );
239 | }
240 |
241 | Widget _rowTextWidget() {
242 | return Row(
243 | mainAxisAlignment: MainAxisAlignment.center,
244 | children: [
245 | Text(
246 | isLoginPage==true? "Don't have account?" : "Have an account?",
247 | style: TextStyle(fontSize: 16, color: Colors.indigo[400]),
248 | ),
249 | InkWell(
250 | onTap: (){
251 | setState(() {
252 | if (isLoginPage==true)
253 | isLoginPage=false;
254 | else
255 | isLoginPage=true;
256 | });
257 | },
258 | child: Text(
259 | isLoginPage==true ?" Sign Up":" Sign In",
260 | style: TextStyle(fontSize: 16, color: Colors.indigo,fontWeight: FontWeight.bold),
261 | ),
262 | ),
263 | ],
264 | );
265 | }
266 | void _submitLogin() {
267 | if (_emailController.text.isNotEmpty &&
268 | _passwordController.text.isNotEmpty) {
269 | BlocProvider.of(context).submitLogin(
270 | email: _emailController.text,
271 | password: _passwordController.text,
272 | );
273 | }
274 | }
275 |
276 | void _submitRegistration() {
277 | if (_emailController.text.isNotEmpty &&
278 | _passwordController.text.isNotEmpty &&
279 | _nameController.text.isNotEmpty) {
280 | BlocProvider.of(context).submitRegistration(
281 | email: _emailController.text,
282 | password: _passwordController.text,
283 | name: _nameController.text,
284 | );
285 | }
286 | }
287 | }
288 |
--------------------------------------------------------------------------------
/lib/presentation/pages/mobile/widget/mobile_message_layout.dart:
--------------------------------------------------------------------------------
1 | import 'package:bubble/bubble.dart';
2 | import 'package:flutter/material.dart';
3 |
4 |
5 | class MobileMessageLayout extends StatelessWidget {
6 | final String uid;
7 | final String type;
8 | final text;
9 | final time;
10 | final color;
11 | final align;
12 | final boxAlignment;
13 | final nip;
14 | final senderName;
15 | final senderId;
16 | final boxMainAxisAlignment;
17 |
18 | const MobileMessageLayout({
19 | Key key,
20 | this.uid,
21 | this.type,
22 | this.text,
23 | this.time,
24 | this.color,
25 | this.align,
26 | this.boxAlignment,
27 | this.nip,
28 | this.senderName,
29 | this.senderId,
30 | this.boxMainAxisAlignment,
31 | }) : super(key: key);
32 |
33 | @override
34 | Widget build(BuildContext context) {
35 | return Column(
36 | crossAxisAlignment: boxAlignment,
37 | children: [
38 | Row(
39 | crossAxisAlignment: CrossAxisAlignment.start,
40 | mainAxisAlignment: boxMainAxisAlignment,
41 | children: [
42 | color == Colors.blue
43 | ?Container(
44 | height: 35,
45 | width: 35,
46 | decoration: BoxDecoration(
47 | border: Border.all(color: Colors.black,width: 2),
48 | borderRadius: BorderRadius.all(Radius.circular(55))
49 | ),
50 | child: Image.asset("assets/profile_default.png"),
51 | ):Text("",style: TextStyle(fontSize: 0),),
52 | Container(
53 | padding: EdgeInsets.all(8),
54 | margin: EdgeInsets.all(3),
55 | child: Bubble(
56 | color: color,
57 | nip: nip,
58 | child: Column(
59 | crossAxisAlignment: CrossAxisAlignment.start,
60 | children: [
61 | color == Colors.green[300]
62 | ? Text(
63 | "Me",
64 | textAlign: align,
65 | style: TextStyle(
66 | fontSize: 18, fontWeight: FontWeight.bold),
67 | )
68 | : Text(
69 | senderName,
70 | textAlign: align,
71 | style: TextStyle(
72 | fontSize: 18, fontWeight: FontWeight.bold),
73 | ),
74 | ConstrainedBox(
75 | constraints: BoxConstraints(
76 | maxWidth: 250
77 | ),
78 | child: Text(
79 | text==""?"":text,
80 | textAlign: align,
81 | style: TextStyle(fontSize: 18),
82 | ),
83 | ),
84 | Text(
85 | time,
86 | textAlign: align,
87 | style: TextStyle(fontSize: 14),
88 | )
89 | ],
90 | ),
91 | ),
92 | ),
93 | ],
94 | )
95 | ],
96 | );
97 | }
98 | }
99 |
100 |
--------------------------------------------------------------------------------
/lib/presentation/pages/tablet/single_chat_page_tablet.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:bubble/bubble.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_bloc/flutter_bloc.dart';
6 | import 'package:group_chat_room_responsive/presentation/bloc/communication/communication_cubit.dart';
7 | import 'package:group_chat_room_responsive/presentation/pages/widget/message_layout.dart';
8 | import 'package:intl/intl.dart';
9 | import 'package:responsive_builder/responsive_builder.dart';
10 |
11 | class SingleChatPageTablet extends StatefulWidget {
12 | final String uid;
13 | final String userName;
14 |
15 | const SingleChatPageTablet({Key key, this.uid, this.userName}) : super(key: key);
16 |
17 | @override
18 | _SingleChatPageTabletState createState() => _SingleChatPageTabletState();
19 | }
20 |
21 | class _SingleChatPageTabletState extends State {
22 | TextEditingController _messageController = TextEditingController();
23 | ScrollController _scrollController=ScrollController();
24 |
25 | @override
26 | void initState() {
27 | BlocProvider.of(context).getTextMessages();
28 | super.initState();
29 | }
30 |
31 | @override
32 | Widget build(BuildContext context) {
33 | return BlocBuilder(
34 | builder: (context,state){
35 | if (state is CommunicationLoaded){
36 | return _bodyWidget(state);
37 | }
38 | return _loadingWidget();
39 | },
40 | );
41 | }
42 | Widget _bodyWidget(CommunicationLoaded messages) {
43 | return Scaffold(
44 | body: Stack(
45 | children: [
46 | Positioned.fill(
47 | child: Image.asset(
48 | "assets/background_img.png",
49 | fit: BoxFit.cover,
50 | ),
51 | ),
52 | Column(
53 | children: [
54 | _headerWidget(),
55 | _listMessagesWidget(messages),
56 | _sendTextMessageWidget(),
57 | ],
58 | ),
59 | ],
60 | ),
61 | );
62 | }
63 | Widget _loadingWidget(){
64 | return Scaffold(
65 | body: Stack(
66 | children: [
67 | Positioned.fill(
68 | child: Image.asset(
69 | "assets/background_img.png",
70 | fit: BoxFit.cover,
71 | ),
72 | ),
73 | Column(
74 | children: [
75 | _headerWidget(),
76 | Expanded(child: Center(child: CircularProgressIndicator(),)),
77 | _sendTextMessageWidget(),
78 | ],
79 | ),
80 | ],
81 | ),
82 | );
83 | }
84 | Widget _headerWidget() {
85 | return Container(
86 | padding: EdgeInsets.symmetric(horizontal: 80),
87 | height: 60,
88 | width: double.infinity,
89 | decoration: BoxDecoration(
90 | gradient: LinearGradient(
91 | colors: [
92 | Colors.indigo[400],
93 | Colors.blue[300],
94 | ],
95 | )),
96 | child: Row(
97 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
98 | children: [
99 | Row(
100 | children: [
101 | Container(
102 | width: 40, height: 40, child: Image.asset("assets/logo.png")),
103 | Text(
104 | "Global Chat Room",
105 | style: TextStyle(
106 | fontSize: 22,
107 | color: Colors.white,
108 | ),
109 | ),
110 | ],
111 | ),
112 | Text(
113 | "${widget.userName}",
114 | style: TextStyle(
115 | fontSize: 22,
116 | color: Colors.white,
117 | ),
118 | )
119 | ],
120 | ),
121 | );
122 | }
123 |
124 | Widget _listMessagesWidget(CommunicationLoaded messages) {
125 | Timer(
126 | Duration(milliseconds: 100),
127 | () => _scrollController
128 | .jumpTo(_scrollController.position.maxScrollExtent));
129 | return Expanded(
130 | child: Container(
131 | margin: EdgeInsets.symmetric(horizontal: 20),
132 | child: ListView.builder(
133 | controller: _scrollController,
134 | shrinkWrap: true,
135 | itemCount: messages.messages.length,
136 | itemBuilder: (_, index) {
137 | return messages.messages[index].senderId ==
138 | widget.uid
139 | ? MessageLayout(
140 | type: messages.messages[index].type,
141 | senderId: messages.messages[index].senderId,
142 | senderName:
143 | messages.messages[index].senderName,
144 | text: messages.messages[index].message,
145 | time: DateFormat('hh:mm a').format(
146 | messages.messages[index].time.toDate()),
147 | color: Colors.green[300],
148 | align: TextAlign.left,
149 | nip: BubbleNip.rightTop,
150 | boxAlignment: CrossAxisAlignment.end,
151 | boxMainAxisAlignment: MainAxisAlignment.end,
152 | uid: widget.uid,)
153 | : MessageLayout(
154 | type: messages.messages[index].type,
155 | senderName:
156 | messages.messages[index].senderName,
157 | text: messages.messages[index].message,
158 | time: DateFormat('hh:mm a').format(
159 | messages.messages[index].time.toDate()),
160 | color: Colors.blue,
161 | align: TextAlign.left,
162 | nip: BubbleNip.leftTop,
163 | boxAlignment: CrossAxisAlignment.start,
164 | boxMainAxisAlignment: MainAxisAlignment.start,
165 | );
166 | },
167 | ),
168 | ),
169 | );
170 | }
171 |
172 | Widget _sendTextMessageWidget() {
173 | return Padding(
174 | padding: const EdgeInsets.only(bottom: 5),
175 | child: Container(
176 | padding: EdgeInsets.symmetric(horizontal: 80),
177 | height: 60,
178 | width: double.infinity,
179 | decoration: BoxDecoration(
180 | color: Colors.white,
181 | borderRadius: BorderRadius.all(Radius.circular(0.0)),
182 | border: Border.all(color: Colors.black.withOpacity(.4), width: 2)),
183 | child: Row(
184 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
185 | children: [
186 | Row(
187 | children: [
188 | _emojiWidget(),
189 | SizedBox(
190 | width: 8,
191 | ),
192 | _textFieldWidget(),
193 | ],
194 | ),
195 | Row(
196 | children: [
197 | _micWidget(),
198 | SizedBox(
199 | width: 8,
200 | ),
201 | _sendMessageButton(),
202 | ],
203 | )
204 | ],
205 | ),
206 | ),
207 | );
208 | }
209 |
210 | _emojiWidget() {
211 | return Container(
212 | height: 50,
213 | width: 50,
214 | decoration: BoxDecoration(
215 | color: Colors.black.withOpacity(.2),
216 | borderRadius: BorderRadius.all(Radius.circular(40))),
217 | child: Icon(
218 | Icons.emoji_symbols,
219 | color: Colors.white,
220 | ),
221 | );
222 | }
223 |
224 | _micWidget() {
225 | return Container(
226 | height: 50,
227 | width: 50,
228 | decoration: BoxDecoration(
229 | color: Colors.black.withOpacity(.2),
230 | borderRadius: BorderRadius.all(Radius.circular(40))),
231 | child: Icon(
232 | Icons.mic,
233 | color: Colors.white,
234 | ),
235 | );
236 | }
237 |
238 | _textFieldWidget() {
239 | return ResponsiveBuilder(
240 | builder: (_, sizingInformation) {
241 | return Container(
242 | width: sizingInformation.screenSize.width * 0.45,
243 | child: ConstrainedBox(
244 | constraints: BoxConstraints(
245 | maxHeight: 60,
246 | ),
247 | child: Scrollbar(
248 | child: TextField(
249 | controller: _messageController,
250 | maxLines: null,
251 | decoration: InputDecoration(
252 | border: InputBorder.none,
253 | hintText: "Type Feel Free <3 ..."),
254 | ),
255 | ),
256 | ),
257 | );
258 | },
259 | );
260 | }
261 |
262 | Widget _sendMessageButton() {
263 | return InkWell(
264 | onTap: () {
265 | if (_messageController.text.isNotEmpty) {
266 | _sendTextMessage();
267 | _messageController.clear();
268 | }
269 | },
270 | child: Container(
271 | height: 50,
272 | width: 50,
273 | decoration: BoxDecoration(
274 | color: Colors.green,
275 | borderRadius: BorderRadius.all(Radius.circular(40))),
276 | child: Icon(
277 | Icons.send,
278 | color: Colors.white,
279 | ),
280 | ),
281 | );
282 | }
283 |
284 | void _sendTextMessage() {
285 | BlocProvider.of(context).sendTextMsg(
286 | uid: widget.uid,
287 | name: widget.userName,
288 | message: _messageController.text);
289 | }
290 | }
291 |
--------------------------------------------------------------------------------
/lib/presentation/pages/tablet/tablet_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:group_chat_room_responsive/presentation/pages/tablet/widgets/left_side_widget.dart';
3 | import 'package:group_chat_room_responsive/presentation/pages/tablet/widgets/right_side_widget.dart';
4 | import 'package:responsive_builder/responsive_builder.dart';
5 |
6 | class TabletPage extends StatelessWidget {
7 | @override
8 | Widget build(BuildContext context) {
9 | return ResponsiveBuilder(
10 | builder: (context,sizingInformation){
11 | return Scaffold(
12 | body: Row(
13 | children: [
14 | LeftSideWidget(sizingInformation: sizingInformation,),
15 | Expanded(child: RightSideWidget(
16 | sizingInformation: sizingInformation,
17 | )),
18 | ],
19 | ),
20 | );
21 | },
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/presentation/pages/tablet/welcome_page_tablet.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_bloc/flutter_bloc.dart';
4 | import 'package:group_chat_room_responsive/data/model/user_model.dart';
5 | import 'package:group_chat_room_responsive/presentation/bloc/auth/auth_cubit.dart';
6 | import 'package:group_chat_room_responsive/presentation/bloc/login/login_cubit.dart';
7 | import 'package:group_chat_room_responsive/presentation/bloc/user/user_cubit.dart';
8 | import 'package:group_chat_room_responsive/presentation/pages/tablet/single_chat_page_tablet.dart';
9 | import 'package:group_chat_room_responsive/presentation/screens/single_chat_screen.dart';
10 | import 'package:lottie/lottie.dart';
11 |
12 | class WelcomePageTablet extends StatefulWidget {
13 | final String uid;
14 |
15 | const WelcomePageTablet({Key key, this.uid}) : super(key: key);
16 | @override
17 | _WelcomePageTabletState createState() => _WelcomePageTabletState();
18 | }
19 |
20 | class _WelcomePageTabletState extends State {
21 |
22 | @override
23 | void initState() {
24 | BlocProvider.of(context).getUsers();
25 | super.initState();
26 | }
27 | @override
28 | Widget build(BuildContext context) {
29 | return BlocBuilder(builder: (_,state){
30 | if (state is UserLoaded){
31 | return _bodyWidget(state);
32 | }
33 | return _loadingWidget();
34 | });
35 | }
36 |
37 | Widget _bodyWidget(UserLoaded users){
38 | final user = users.users.firstWhere((user) => user.uid == widget.uid,orElse: () => UserModel());
39 | return Scaffold(
40 | body: Stack(
41 | children: [
42 | Container(
43 | decoration: BoxDecoration(
44 | gradient: LinearGradient(
45 | colors: [
46 | Colors.indigo[400],
47 | Colors.blue[300],
48 | ],
49 | )),
50 | ),
51 | Align(
52 | alignment: Alignment.topCenter,
53 | child: Lottie.asset("assets/congratulation.json"),
54 | ),
55 | Align(
56 | alignment: Alignment.bottomRight,
57 | child: Lottie.asset("assets/bubble.json"),
58 | ),
59 | Align(
60 | alignment: Alignment.topCenter,
61 | child: Container(
62 | margin: EdgeInsets.only(top: 100),
63 | child: Text(
64 | "Welcome ${user.name}",
65 | style: TextStyle(
66 | fontSize: 25,
67 | color: Colors.white,
68 | fontWeight: FontWeight.bold,
69 | ),
70 | )),
71 | ),
72 | _joinGlobalChatButton(user.name),
73 | _logOutWidget(),
74 | ],
75 | ),
76 | );
77 | }
78 |
79 | Widget _loadingWidget(){
80 | return Scaffold(
81 | body: Stack(
82 | children: [
83 | Container(
84 | decoration: BoxDecoration(
85 | gradient: LinearGradient(
86 | colors: [
87 | Colors.indigo[400],
88 | Colors.blue[300],
89 | ],
90 | )),
91 | ),
92 | Align(
93 | alignment: Alignment.center,
94 | child: CircularProgressIndicator(),
95 | ),
96 | ],
97 | ),
98 | );
99 | }
100 |
101 | Widget _joinGlobalChatButton(String name) {
102 | return Align(
103 | alignment: Alignment.center,
104 | child: Column(
105 | mainAxisAlignment: MainAxisAlignment.center,
106 | children: [
107 | Text(
108 | "Join Us For Fun",
109 | style: TextStyle(
110 | fontSize: 25,
111 | fontWeight: FontWeight.bold,
112 | ),
113 | ),
114 | SizedBox(
115 | height: 30,
116 | ),
117 | InkWell(
118 | onTap: (){
119 | Navigator.push(
120 | context,
121 | MaterialPageRoute(
122 | builder: (_) => SingleChatScreen(username: name,uid: widget.uid,),
123 | ),
124 | );
125 | },
126 | child: Container(
127 | width: 250,
128 | height: 70,
129 | alignment: Alignment.center,
130 | decoration: BoxDecoration(
131 | color: Colors.white.withOpacity(.3),
132 | borderRadius: BorderRadius.all(Radius.circular(20)),
133 | border: Border.all(color: Colors.white60, width: 2)),
134 | child: Text(
135 | "Join",
136 | style: TextStyle(fontSize: 25),
137 | ),
138 | ),
139 | ),
140 | ],
141 | ),
142 | );
143 | }
144 | Widget _logOutWidget() {
145 | return Align(
146 | alignment: Alignment.bottomLeft,
147 | child: InkWell(
148 | onTap: (){
149 | //TODO:Logout
150 | BlocProvider.of(context).loggedOut();
151 | BlocProvider.of(context).submitSignOut();
152 | },
153 | child: Container(
154 | margin: EdgeInsets.only(left: 15,bottom: 15),
155 | padding: EdgeInsets.all(10),
156 | decoration: BoxDecoration(
157 | color: Colors.white.withOpacity(.3),
158 | borderRadius: BorderRadius.circular(30),
159 | ),
160 | child: Icon(
161 | Icons.exit_to_app,
162 | size: 30,
163 | ),
164 | ),
165 | ),
166 | );
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/lib/presentation/pages/tablet/widgets/left_side_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/painting.dart';
3 | import 'package:flutter/widgets.dart';
4 | import 'package:lottie/lottie.dart';
5 | import 'package:responsive_builder/responsive_builder.dart';
6 |
7 | class LeftSideWidget extends StatelessWidget {
8 | final SizingInformation sizingInformation;
9 |
10 | const LeftSideWidget({Key key, this.sizingInformation}) : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Container(
15 | width: sizingInformation.screenSize.width * 0.55,
16 | height: double.infinity,
17 | decoration: BoxDecoration(
18 | gradient: LinearGradient(
19 | colors: [
20 | Colors.indigo[400],
21 | Colors.blue[300],
22 | ],
23 | )),
24 | child: Container(
25 | child: Stack(
26 | children: [
27 | _loginButton(),
28 | _bgImageWidget(),
29 | _welcomeTextWidget(),
30 | Positioned(
31 | left: -150,
32 | bottom: -150,
33 | child: Image.asset(
34 | "assets/shape.png",
35 | color: Colors.white.withOpacity(.2),
36 | ))
37 | ],
38 | ),
39 | ),
40 | );
41 | }
42 |
43 | Widget _loginButton() {
44 | return Align(
45 | alignment: Alignment.topRight,
46 | child: Container(
47 | margin: EdgeInsets.symmetric(horizontal: 20, vertical: 20),
48 | padding: EdgeInsets.symmetric(horizontal: 20, vertical: 5),
49 | decoration: BoxDecoration(
50 | borderRadius: BorderRadius.all(Radius.circular(15)),
51 | border: Border.all(color: Colors.white60, width: 1.50),
52 | ),
53 | child: Text(
54 | "LOGIN",
55 | style: TextStyle(fontSize: 16, color: Colors.white60),
56 | )),
57 | );
58 | }
59 |
60 | _bgImageWidget() {
61 | return Align(
62 | alignment: Alignment.center,
63 | child: Lottie.asset("assets/img.json"),
64 | );
65 | }
66 |
67 | Widget _welcomeTextWidget() {
68 | return Positioned(
69 | left: 35,
70 | bottom: 30,
71 | child: Column(
72 | crossAxisAlignment: CrossAxisAlignment.start,
73 | children: [
74 | Container(
75 | width: sizingInformation.screenSize.width * 0.45,
76 | child: Text(
77 | "WELCOME TO eTechViral",
78 | style: TextStyle(
79 | fontSize: 30, color: Colors.white, fontWeight: FontWeight.bold),
80 | ),
81 | ),
82 | SizedBox(
83 | height: 20,
84 | ),
85 | Container(
86 | width: sizingInformation.screenSize.width * 0.45,
87 | child: Text(
88 | "Flutter is changing the app development world. if you want to improve your flutter skill then join our channel because we try to upload one video per week. eTechViral :- flutter and dart app development tutorials crafted to make you win jobs.",
89 | textAlign: TextAlign.start,
90 | style: TextStyle(color: Colors.white60, fontSize: 16),
91 | ),
92 | ),
93 | SizedBox(
94 | height: 20,
95 | ),
96 | Container(
97 | padding: EdgeInsets.symmetric(horizontal: 20, vertical: 5),
98 | decoration: BoxDecoration(
99 | borderRadius: BorderRadius.all(Radius.circular(15)),
100 | border: Border.all(color: Colors.white60, width: 1.50),
101 | ),
102 | child: Text(
103 | "SIGN IN",
104 | style: TextStyle(fontSize: 16, color: Colors.white60),
105 | )),
106 | ],
107 | ),
108 | );
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/lib/presentation/pages/tablet/widgets/right_side_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_bloc/flutter_bloc.dart';
4 | import 'package:group_chat_room_responsive/presentation/bloc/auth/auth_cubit.dart';
5 | import 'package:group_chat_room_responsive/presentation/bloc/login/login_cubit.dart';
6 | import 'package:lottie/lottie.dart';
7 | import 'package:responsive_builder/responsive_builder.dart';
8 |
9 | class RightSideWidget extends StatefulWidget {
10 | final SizingInformation sizingInformation;
11 |
12 | const RightSideWidget({Key key, this.sizingInformation}) : super(key: key);
13 |
14 | @override
15 | _RightSideWidgetState createState() => _RightSideWidgetState();
16 | }
17 |
18 | class _RightSideWidgetState extends State {
19 |
20 | TextEditingController _nameController;
21 | TextEditingController _emailController;
22 | TextEditingController _passwordController;
23 |
24 | bool isLoginPage=true;
25 |
26 | @override
27 | void initState() {
28 | _nameController=TextEditingController();
29 | _emailController=TextEditingController();
30 | _passwordController=TextEditingController();
31 | super.initState();
32 | }
33 | @override
34 | void dispose() {
35 | _nameController.dispose();
36 | _emailController.dispose();
37 | _passwordController.dispose();
38 | super.dispose();
39 | }
40 |
41 | @override
42 | Widget build(BuildContext context) {
43 | return BlocConsumer(
44 | builder: (context, state) {
45 | if (state is LoginLoading) {
46 | return _loadingWidget();
47 | }
48 | return _bodyWidget();
49 | },
50 | listener: (context, state) {
51 | if (state is LoginSuccess){
52 | BlocProvider.of(context).loggedIn();
53 | }
54 | },
55 | );
56 | }
57 | Widget _bodyWidget(){
58 | return Container(
59 | decoration: BoxDecoration(
60 | color: Colors.white,
61 | ),
62 | height: double.infinity,
63 | padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
64 | child: Column(
65 | mainAxisAlignment: MainAxisAlignment.center,
66 | children: [
67 | _imageWidget(),
68 | SizedBox(
69 | height: 15,
70 | ),
71 | _fromWidget(),
72 | SizedBox(
73 | height: 15,
74 | ),
75 | _buttonWidget(),
76 | SizedBox(
77 | height: 40,
78 | ),
79 | Align(
80 | alignment: Alignment.bottomCenter,
81 | child: _rowTextWidget(),
82 | ),
83 | ],
84 | ),
85 | );
86 | }
87 | Widget _loadingWidget(){
88 | return Container(
89 | decoration: BoxDecoration(
90 | color: Colors.white,
91 | ),
92 | height: double.infinity,
93 | padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
94 | child: Column(
95 | mainAxisAlignment: MainAxisAlignment.center,
96 | children: [
97 | _imageWidget(),
98 | SizedBox(
99 | height: 15,
100 | ),
101 | _fromWidget(),
102 | SizedBox(
103 | height: 15,
104 | ),
105 | _buttonWidget(),
106 | SizedBox(
107 | height: 40,
108 | ),
109 | Align(
110 | alignment: Alignment.bottomCenter,
111 | child: Lottie.asset("assets/loading.json"),
112 | ),
113 | ],
114 | ),
115 | );
116 | }
117 | Widget _imageWidget() {
118 | return Container(
119 | height: 60,
120 | width: 60,
121 | child: Image.asset("assets/profile.png"),
122 | );
123 | }
124 |
125 | Widget _fromWidget() {
126 | return Column(
127 | children: [
128 | isLoginPage==true?Text("",style: TextStyle(fontSize: 0),):Container(
129 | height: 60,
130 | alignment: Alignment.center,
131 | decoration: BoxDecoration(
132 | borderRadius: BorderRadius.all(Radius.circular(40)),
133 | border: Border.all(color: Colors.grey, width: 1.0),
134 | ),
135 | child: TextField(
136 | controller: _nameController,
137 | decoration: InputDecoration(
138 | border: InputBorder.none,
139 | hintText: "User Name",
140 | prefixIcon: Icon(Icons.person_outline),
141 | ),
142 | ),
143 | ),
144 | isLoginPage==true?Text("",style: TextStyle(fontSize: 0),):SizedBox(
145 | height: 20,
146 | ),
147 | Container(
148 | height: 60,
149 | alignment: Alignment.center,
150 | decoration: BoxDecoration(
151 | borderRadius: BorderRadius.all(Radius.circular(40)),
152 | border: Border.all(color: Colors.grey, width: 1.0),
153 | ),
154 | child: TextField(
155 | controller: _emailController,
156 | decoration: InputDecoration(
157 | border: InputBorder.none,
158 | hintText: "Email Address",
159 | prefixIcon: Icon(Icons.alternate_email),
160 | ),
161 | ),
162 | ),
163 | SizedBox(
164 | height: 20,
165 | ),
166 | Container(
167 | height: 60,
168 | alignment: Alignment.center,
169 | decoration: BoxDecoration(
170 | borderRadius: BorderRadius.all(Radius.circular(40)),
171 | border: Border.all(color: Colors.grey, width: 1.0),
172 | ),
173 | child: TextField(
174 | controller: _passwordController,
175 | obscureText: true,
176 | decoration: InputDecoration(
177 | border: InputBorder.none,
178 | hintText: "Password",
179 | prefixIcon: Icon(Icons.lock_outline),
180 | ),
181 | ),
182 | ),
183 | ],
184 | );
185 | }
186 |
187 | Widget _buttonWidget() {
188 | return InkWell(
189 | onTap: (){
190 | if (isLoginPage == true) {
191 | _submitLogin();
192 | } else {
193 | _submitRegistration();
194 | }
195 | },
196 | child: Container(
197 | margin: EdgeInsets.symmetric(horizontal: 10),
198 | width: widget.sizingInformation.screenSize.width,
199 | alignment: Alignment.center,
200 | padding: EdgeInsets.symmetric(vertical: 14),
201 | decoration: BoxDecoration(
202 | color: Colors.indigo,
203 | borderRadius: BorderRadius.all(Radius.circular(50)),
204 | ),
205 | child: Text(
206 | isLoginPage==true?"LOGIN":"REGISTER",
207 | style: TextStyle(fontSize: 18, color: Colors.white),
208 | ),
209 | ),
210 | );
211 | }
212 |
213 | Widget _rowTextWidget() {
214 | return Row(
215 | mainAxisAlignment: MainAxisAlignment.center,
216 | children: [
217 | Text(
218 | isLoginPage==true? "Don't have account?" : "Have an account?",
219 | style: TextStyle(fontSize: 16, color: Colors.indigo[400]),
220 | ),
221 | InkWell(
222 | onTap: (){
223 | setState(() {
224 | if (isLoginPage==true)
225 | isLoginPage=false;
226 | else
227 | isLoginPage=true;
228 | });
229 | },
230 | child: Text(
231 | isLoginPage==true ?" Sign Up":" Sign In",
232 | style: TextStyle(fontSize: 16, color: Colors.indigo,fontWeight: FontWeight.bold),
233 | ),
234 | ),
235 | ],
236 | );
237 | }
238 | void _submitLogin() {
239 | if (_emailController.text.isNotEmpty &&
240 | _passwordController.text.isNotEmpty) {
241 | BlocProvider.of(context).submitLogin(
242 | email: _emailController.text,
243 | password: _passwordController.text,
244 | );
245 | }
246 | }
247 |
248 | void _submitRegistration() {
249 | if (_emailController.text.isNotEmpty &&
250 | _passwordController.text.isNotEmpty &&
251 | _nameController.text.isNotEmpty) {
252 | BlocProvider.of(context).submitRegistration(
253 | email: _emailController.text,
254 | password: _passwordController.text,
255 | name: _nameController.text,
256 | );
257 | }
258 | }
259 | }
260 |
--------------------------------------------------------------------------------
/lib/presentation/pages/web/single_chat_page_web.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:bubble/bubble.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_bloc/flutter_bloc.dart';
6 | import 'package:group_chat_room_responsive/presentation/bloc/communication/communication_cubit.dart';
7 | import 'package:group_chat_room_responsive/presentation/pages/widget/message_layout.dart';
8 | import 'package:intl/intl.dart';
9 | import 'package:responsive_builder/responsive_builder.dart';
10 |
11 | class SingleChatPageWeb extends StatefulWidget {
12 | final String uid;
13 | final String userName;
14 |
15 | const SingleChatPageWeb({Key key, this.uid, this.userName}) : super(key: key);
16 |
17 | @override
18 | _SingleChatPageWebState createState() => _SingleChatPageWebState();
19 | }
20 |
21 | class _SingleChatPageWebState extends State {
22 | TextEditingController _messageController = TextEditingController();
23 | ScrollController _scrollController =ScrollController();
24 |
25 | @override
26 | void initState() {
27 | BlocProvider.of(context).getTextMessages();
28 | super.initState();
29 | }
30 |
31 | @override
32 | Widget build(BuildContext context) {
33 | return BlocBuilder(
34 | builder: (context,state){
35 | if (state is CommunicationLoaded){
36 | return _bodyWidget(state);
37 | }
38 | return _loadingWidget();
39 | },
40 | );
41 | }
42 | Widget _bodyWidget(CommunicationLoaded messages) {
43 | return Scaffold(
44 | body: Stack(
45 | children: [
46 | Positioned.fill(
47 | child: Image.asset(
48 | "assets/background_img.png",
49 | fit: BoxFit.cover,
50 | ),
51 | ),
52 | Column(
53 | children: [
54 | _headerWidget(),
55 | _listMessagesWidget(messages),
56 | _sendTextMessageWidget(),
57 | ],
58 | ),
59 | ],
60 | ),
61 | );
62 | }
63 | Widget _loadingWidget(){
64 | return Scaffold(
65 | body: Stack(
66 | children: [
67 | Positioned.fill(
68 | child: Image.asset(
69 | "assets/background_img.png",
70 | fit: BoxFit.cover,
71 | ),
72 | ),
73 | Column(
74 | children: [
75 | _headerWidget(),
76 | Expanded(child: Center(child: CircularProgressIndicator(),)),
77 | _sendTextMessageWidget(),
78 | ],
79 | ),
80 | ],
81 | ),
82 | );
83 | }
84 | Widget _headerWidget() {
85 | return Container(
86 | padding: EdgeInsets.symmetric(horizontal: 80),
87 | height: 60,
88 | width: double.infinity,
89 | decoration: BoxDecoration(
90 | gradient: LinearGradient(
91 | colors: [
92 | Colors.indigo[400],
93 | Colors.blue[300],
94 | ],
95 | )),
96 | child: Row(
97 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
98 | children: [
99 | Row(
100 | children: [
101 | Container(
102 | width: 40, height: 40, child: Image.asset("assets/logo.png")),
103 | Text(
104 | "Global Chat Room",
105 | style: TextStyle(
106 | fontSize: 22,
107 | color: Colors.white,
108 | ),
109 | ),
110 | ],
111 | ),
112 | Text(
113 | "${widget.userName}",
114 | style: TextStyle(
115 | fontSize: 22,
116 | color: Colors.white,
117 | ),
118 | )
119 | ],
120 | ),
121 | );
122 | }
123 |
124 | Widget _listMessagesWidget(CommunicationLoaded messages) {
125 | Timer(
126 | Duration(milliseconds: 100),
127 | () => _scrollController
128 | .jumpTo(_scrollController.position.maxScrollExtent));
129 |
130 | return Expanded(
131 | child: Container(
132 | margin: EdgeInsets.symmetric(horizontal: 20),
133 | child: ListView.builder(
134 | controller: _scrollController,
135 | shrinkWrap: true,
136 | itemCount: messages.messages.length,
137 | itemBuilder: (_, index) {
138 | return messages.messages[index].senderId ==
139 | widget.uid
140 | ? MessageLayout(
141 | type: messages.messages[index].type,
142 | senderId: messages.messages[index].senderId,
143 | senderName:
144 | messages.messages[index].senderName,
145 | text: messages.messages[index].message,
146 | time: DateFormat('hh:mm a').format(
147 | messages.messages[index].time.toDate()),
148 | color: Colors.green[300],
149 | align: TextAlign.left,
150 | nip: BubbleNip.rightTop,
151 | boxAlignment: CrossAxisAlignment.end,
152 | boxMainAxisAlignment: MainAxisAlignment.end,
153 | uid: widget.uid,)
154 | : MessageLayout(
155 | type: messages.messages[index].type,
156 | senderName:
157 | messages.messages[index].senderName,
158 | text: messages.messages[index].message,
159 | time: DateFormat('hh:mm a').format(
160 | messages.messages[index].time.toDate()),
161 | color: Colors.blue,
162 | align: TextAlign.left,
163 | nip: BubbleNip.leftTop,
164 | boxAlignment: CrossAxisAlignment.start,
165 | boxMainAxisAlignment: MainAxisAlignment.start,
166 | );
167 | },
168 | ),
169 | ),
170 | );
171 | }
172 |
173 | Widget _sendTextMessageWidget() {
174 | return Padding(
175 | padding: const EdgeInsets.only(bottom: 5),
176 | child: Container(
177 | padding: EdgeInsets.symmetric(horizontal: 80),
178 | height: 60,
179 | width: double.infinity,
180 | decoration: BoxDecoration(
181 | color: Colors.white,
182 | borderRadius: BorderRadius.all(Radius.circular(0.0)),
183 | border: Border.all(color: Colors.black.withOpacity(.4), width: 2)),
184 | child: Row(
185 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
186 | children: [
187 | Row(
188 | children: [
189 | _emojiWidget(),
190 | SizedBox(
191 | width: 8,
192 | ),
193 | _textFieldWidget(),
194 | ],
195 | ),
196 | Row(
197 | children: [
198 | _micWidget(),
199 | SizedBox(
200 | width: 8,
201 | ),
202 | _sendMessageButton(),
203 | ],
204 | )
205 | ],
206 | ),
207 | ),
208 | );
209 | }
210 |
211 | _emojiWidget() {
212 | return Container(
213 | height: 50,
214 | width: 50,
215 | decoration: BoxDecoration(
216 | color: Colors.black.withOpacity(.2),
217 | borderRadius: BorderRadius.all(Radius.circular(40))),
218 | child: Icon(
219 | Icons.emoji_symbols,
220 | color: Colors.white,
221 | ),
222 | );
223 | }
224 |
225 | _micWidget() {
226 | return Container(
227 | height: 50,
228 | width: 50,
229 | decoration: BoxDecoration(
230 | color: Colors.black.withOpacity(.2),
231 | borderRadius: BorderRadius.all(Radius.circular(40))),
232 | child: Icon(
233 | Icons.mic,
234 | color: Colors.white,
235 | ),
236 | );
237 | }
238 |
239 | _textFieldWidget() {
240 | return ResponsiveBuilder(
241 | builder: (_, sizingInformation) {
242 | return Container(
243 | width: sizingInformation.screenSize.width * 0.65,
244 | child: ConstrainedBox(
245 | constraints: BoxConstraints(
246 | maxHeight: 60,
247 | ),
248 | child: Scrollbar(
249 | child: TextField(
250 | controller: _messageController,
251 | maxLines: null,
252 | decoration: InputDecoration(
253 | border: InputBorder.none,
254 | hintText: "Type Feel Free <3 ..."),
255 | ),
256 | ),
257 | ),
258 | );
259 | },
260 | );
261 | }
262 |
263 | Widget _sendMessageButton() {
264 | return InkWell(
265 | onTap: () {
266 | if (_messageController.text.isNotEmpty) {
267 | _sendTextMessage();
268 | _messageController.clear();
269 | }
270 | },
271 | child: Container(
272 | height: 50,
273 | width: 50,
274 | decoration: BoxDecoration(
275 | color: Colors.green,
276 | borderRadius: BorderRadius.all(Radius.circular(40))),
277 | child: Icon(
278 | Icons.send,
279 | color: Colors.white,
280 | ),
281 | ),
282 | );
283 | }
284 |
285 | void _sendTextMessage() {
286 | BlocProvider.of(context).sendTextMsg(
287 | uid: widget.uid,
288 | name: widget.userName,
289 | message: _messageController.text);
290 | }
291 | }
292 |
--------------------------------------------------------------------------------
/lib/presentation/pages/web/web_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:group_chat_room_responsive/presentation/pages/web/widgets/left_side_widget.dart';
3 | import 'package:group_chat_room_responsive/presentation/pages/web/widgets/right_side_widget.dart';
4 | import 'package:responsive_builder/responsive_builder.dart';
5 |
6 | class WebPage extends StatelessWidget {
7 | final SizingInformation sizingInformation;
8 |
9 | const WebPage({Key key, this.sizingInformation}) : super(key: key);
10 | @override
11 | Widget build(BuildContext context) {
12 | return Scaffold(
13 | body: Container(
14 | child: Row(
15 | children: [
16 | LeftSideWidget(sizingInformation: sizingInformation,),
17 | Expanded(child: RightSideWidget(
18 | sizingInformation: sizingInformation,
19 | )),
20 | ],
21 | ),
22 | ),
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/presentation/pages/web/welcome_page_web.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_bloc/flutter_bloc.dart';
4 | import 'package:group_chat_room_responsive/data/model/user_model.dart';
5 | import 'package:group_chat_room_responsive/presentation/bloc/auth/auth_cubit.dart';
6 | import 'package:group_chat_room_responsive/presentation/bloc/login/login_cubit.dart';
7 | import 'package:group_chat_room_responsive/presentation/bloc/user/user_cubit.dart';
8 | import 'package:group_chat_room_responsive/presentation/pages/web/single_chat_page_web.dart';
9 | import 'package:group_chat_room_responsive/presentation/screens/single_chat_screen.dart';
10 | import 'package:lottie/lottie.dart';
11 |
12 | class WelcomePageWeb extends StatefulWidget {
13 | final String uid;
14 |
15 | const WelcomePageWeb({Key key, this.uid}) : super(key: key);
16 |
17 | @override
18 | _WelcomePageWebState createState() => _WelcomePageWebState();
19 | }
20 |
21 | class _WelcomePageWebState extends State {
22 | @override
23 | void initState() {
24 | BlocProvider.of(context).getUsers();
25 | super.initState();
26 | }
27 |
28 | @override
29 | Widget build(BuildContext context) {
30 | return BlocBuilder(builder: (_, state) {
31 | if (state is UserLoaded) {
32 | return _bodyWidget(state);
33 | }
34 | return _loadingWidget();
35 | });
36 | }
37 |
38 | Widget _bodyWidget(UserLoaded users) {
39 | final user = users.users.firstWhere((user) => user.uid == widget.uid,
40 | orElse: () => UserModel());
41 | return Scaffold(
42 | body: Stack(
43 | children: [
44 | Container(
45 | decoration: BoxDecoration(
46 | gradient: LinearGradient(
47 | colors: [
48 | Colors.indigo[400],
49 | Colors.blue[300],
50 | ],
51 | )),
52 | ),
53 | Align(
54 | alignment: Alignment.topCenter,
55 | child: Lottie.asset(
56 | "assets/congratulation.json",
57 | ),
58 | ),
59 | Align(
60 | alignment: Alignment.bottomRight,
61 | child: Lottie.asset("assets/bubble.json"),
62 | ),
63 | Align(
64 | alignment: Alignment.topCenter,
65 | child: Container(
66 | margin: EdgeInsets.only(top: 150),
67 | child: Text(
68 | "Welcome ${user.name}",
69 | style: TextStyle(
70 | fontSize: 30,
71 | color: Colors.white,
72 | fontWeight: FontWeight.bold,
73 | ),
74 | )),
75 | ),
76 | _joinGlobalChatButton(name: user.name),
77 | _logOutWidget(),
78 | ],
79 | ),
80 | );
81 | }
82 |
83 | Widget _loadingWidget() {
84 | return Scaffold(
85 | body: Stack(
86 | children: [
87 | Container(
88 | decoration: BoxDecoration(
89 | gradient: LinearGradient(
90 | colors: [
91 | Colors.indigo[400],
92 | Colors.blue[300],
93 | ],
94 | )),
95 | ),
96 | Align(
97 | alignment: Alignment.center,
98 | child: CircularProgressIndicator(),
99 | ),
100 | ],
101 | ),
102 | );
103 | }
104 |
105 | Widget _joinGlobalChatButton({String name}) {
106 | return Align(
107 | alignment: Alignment.center,
108 | child: Center(
109 | child: Column(
110 | mainAxisAlignment: MainAxisAlignment.center,
111 | children: [
112 | Text(
113 | "Join Us For Fun",
114 | style: TextStyle(
115 | fontSize: 30,
116 | fontWeight: FontWeight.bold,
117 | ),
118 | ),
119 | SizedBox(
120 | height: 30,
121 | ),
122 | InkWell(
123 | onTap: () {
124 | Navigator.push(
125 | context,
126 | MaterialPageRoute(
127 | builder: (_) => SingleChatScreen(username: name,uid: widget.uid,),
128 | ),
129 | );
130 | },
131 | child: Container(
132 | width: 250,
133 | height: 70,
134 | alignment: Alignment.center,
135 | decoration: BoxDecoration(
136 | color: Colors.white.withOpacity(.3),
137 | borderRadius: BorderRadius.all(Radius.circular(20)),
138 | border: Border.all(color: Colors.white60, width: 2)),
139 | child: Text(
140 | "Join",
141 | style: TextStyle(fontSize: 30),
142 | ),
143 | ),
144 | ),
145 | ],
146 | ),
147 | ),
148 | );
149 | }
150 |
151 | Widget _logOutWidget() {
152 | return Align(
153 | alignment: Alignment.bottomLeft,
154 | child: InkWell(
155 | onTap: () {
156 | //TODO:Logout
157 | BlocProvider.of(context).loggedOut();
158 | BlocProvider.of(context).submitSignOut();
159 | },
160 | child: Container(
161 | margin: EdgeInsets.only(left: 15, bottom: 15),
162 | padding: EdgeInsets.all(10),
163 | decoration: BoxDecoration(
164 | color: Colors.white.withOpacity(.3),
165 | borderRadius: BorderRadius.circular(30),
166 | ),
167 | child: Icon(
168 | Icons.exit_to_app,
169 | size: 30,
170 | ),
171 | ),
172 | ),
173 | );
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/lib/presentation/pages/web/widgets/left_side_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/painting.dart';
3 | import 'package:flutter/widgets.dart';
4 | import 'package:lottie/lottie.dart';
5 | import 'package:responsive_builder/responsive_builder.dart';
6 |
7 | class LeftSideWidget extends StatelessWidget {
8 | final SizingInformation sizingInformation;
9 |
10 | const LeftSideWidget({Key key, this.sizingInformation}) : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Container(
15 | width: sizingInformation.screenSize.width * 0.65,
16 | height: double.infinity,
17 | decoration: BoxDecoration(
18 | gradient: LinearGradient(
19 | colors: [
20 | Colors.indigo[400],
21 | Colors.blue[300],
22 | ],
23 | )),
24 | child: Container(
25 | child: Stack(
26 | children: [
27 | _loginButton(),
28 | _bgImageWidget(),
29 | _welcomeTextWidget(),
30 | Positioned(
31 | left: -150,
32 | bottom: -150,
33 | child: Image.asset(
34 | "assets/shape.png",
35 | color: Colors.white.withOpacity(.2),
36 | ))
37 | ],
38 | ),
39 | ),
40 | );
41 | }
42 |
43 | Widget _loginButton() {
44 | return Align(
45 | alignment: Alignment.topRight,
46 | child: Container(
47 | margin: EdgeInsets.symmetric(horizontal: 20, vertical: 20),
48 | padding: EdgeInsets.symmetric(horizontal: 20, vertical: 5),
49 | decoration: BoxDecoration(
50 | borderRadius: BorderRadius.all(Radius.circular(15)),
51 | border: Border.all(color: Colors.white60, width: 1.50),
52 | ),
53 | child: Text(
54 | "LOGIN",
55 | style: TextStyle(fontSize: 16, color: Colors.white60),
56 | )),
57 | );
58 | }
59 |
60 | _bgImageWidget() {
61 | return Align(
62 | alignment: Alignment.center,
63 | child: Lottie.asset("assets/img.json"),
64 | );
65 | }
66 |
67 | Widget _welcomeTextWidget() {
68 | return Positioned(
69 | left: 35,
70 | bottom: 30,
71 | child: Column(
72 | crossAxisAlignment: CrossAxisAlignment.start,
73 | children: [
74 | Text(
75 | "WELCOME TO eTechViral",
76 | style: TextStyle(
77 | fontSize: 30, color: Colors.white, fontWeight: FontWeight.bold),
78 | ),
79 | SizedBox(
80 | height: 20,
81 | ),
82 | Container(
83 | width: sizingInformation.screenSize.width * 0.60,
84 | child: Text(
85 | "Flutter is changing the app development world. if you want to improve your flutter skill then join our channel because we try to upload one video per week. eTechViral :- flutter and dart app development tutorials crafted to make you win jobs.",
86 | textAlign: TextAlign.start,
87 | style: TextStyle(color: Colors.white60, fontSize: 16),
88 | ),
89 | ),
90 | SizedBox(
91 | height: 20,
92 | ),
93 | Container(
94 | padding: EdgeInsets.symmetric(horizontal: 20, vertical: 5),
95 | decoration: BoxDecoration(
96 | borderRadius: BorderRadius.all(Radius.circular(15)),
97 | border: Border.all(color: Colors.white60, width: 1.50),
98 | ),
99 | child: Text(
100 | "SIGN IN",
101 | style: TextStyle(fontSize: 16, color: Colors.white60),
102 | )),
103 | ],
104 | ),
105 | );
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/lib/presentation/pages/web/widgets/right_side_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_bloc/flutter_bloc.dart';
4 | import 'package:group_chat_room_responsive/presentation/bloc/auth/auth_cubit.dart';
5 | import 'package:group_chat_room_responsive/presentation/bloc/login/login_cubit.dart';
6 | import 'package:lottie/lottie.dart';
7 | import 'package:responsive_builder/responsive_builder.dart';
8 |
9 | class RightSideWidget extends StatefulWidget {
10 | final SizingInformation sizingInformation;
11 |
12 | const RightSideWidget({Key key, this.sizingInformation}) : super(key: key);
13 |
14 | @override
15 | _RightSideWidgetState createState() => _RightSideWidgetState();
16 | }
17 |
18 | class _RightSideWidgetState extends State {
19 | TextEditingController _nameController;
20 | TextEditingController _emailController;
21 | TextEditingController _passwordController;
22 |
23 | bool isLoginPage = true;
24 |
25 | @override
26 | void initState() {
27 | _nameController = TextEditingController();
28 | _emailController = TextEditingController();
29 | _passwordController = TextEditingController();
30 | super.initState();
31 | }
32 |
33 | @override
34 | void dispose() {
35 | _nameController.dispose();
36 | _emailController.dispose();
37 | _passwordController.dispose();
38 | super.dispose();
39 | }
40 |
41 | @override
42 | Widget build(BuildContext context) {
43 | return BlocConsumer(
44 | builder: (context, state) {
45 | if (state is LoginLoading) {
46 | return _loadingWidget();
47 | }
48 | return _bodyWidget();
49 | },
50 | listener: (context, state) {
51 | if (state is LoginSuccess){
52 | BlocProvider.of(context).loggedIn();
53 | }
54 | },
55 | );
56 | }
57 |
58 | Widget _loadingWidget() {
59 | return Container(
60 | decoration: BoxDecoration(
61 | color: Colors.white,
62 | ),
63 | height: double.infinity,
64 | padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
65 | child: Column(
66 | mainAxisAlignment: MainAxisAlignment.center,
67 | children: [
68 | _imageWidget(),
69 | SizedBox(
70 | height: 15,
71 | ),
72 | _fromWidget(),
73 | SizedBox(
74 | height: 15,
75 | ),
76 | _buttonWidget(),
77 | SizedBox(
78 | height: 40,
79 | ),
80 | Align(
81 | alignment: Alignment.bottomCenter,
82 | child: _rowTextWidget(),
83 | ),
84 | Align(
85 | alignment: Alignment.bottomCenter,
86 | child: Lottie.asset("assets/loading.json"),
87 | ),
88 | ],
89 | ),
90 | );
91 | }
92 |
93 | Widget _bodyWidget() {
94 | return Container(
95 | decoration: BoxDecoration(
96 | color: Colors.white,
97 | ),
98 | height: double.infinity,
99 | padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
100 | child: Column(
101 | mainAxisAlignment: MainAxisAlignment.center,
102 | children: [
103 | _imageWidget(),
104 | SizedBox(
105 | height: 15,
106 | ),
107 | _fromWidget(),
108 | SizedBox(
109 | height: 15,
110 | ),
111 | _buttonWidget(),
112 | SizedBox(
113 | height: 40,
114 | ),
115 | Align(
116 | alignment: Alignment.bottomCenter,
117 | child: _rowTextWidget(),
118 | ),
119 | ],
120 | ),
121 | );
122 | }
123 |
124 | Widget _imageWidget() {
125 | return Container(
126 | height: 60,
127 | width: 60,
128 | child: Image.asset("assets/profile.png"),
129 | );
130 | }
131 |
132 | Widget _fromWidget() {
133 | return Column(
134 | children: [
135 | isLoginPage == true
136 | ? Text(
137 | "",
138 | style: TextStyle(fontSize: 0),
139 | )
140 | : Container(
141 | height: 60,
142 | alignment: Alignment.center,
143 | decoration: BoxDecoration(
144 | borderRadius: BorderRadius.all(Radius.circular(40)),
145 | border: Border.all(color: Colors.grey, width: 1.0),
146 | ),
147 | child: TextField(
148 | controller: _nameController,
149 | decoration: InputDecoration(
150 | border: InputBorder.none,
151 | hintText: "User Name",
152 | prefixIcon: Icon(Icons.person_outline),
153 | ),
154 | ),
155 | ),
156 | isLoginPage == true
157 | ? Text(
158 | "",
159 | style: TextStyle(fontSize: 0),
160 | )
161 | : SizedBox(
162 | height: 20,
163 | ),
164 | Container(
165 | height: 60,
166 | alignment: Alignment.center,
167 | decoration: BoxDecoration(
168 | borderRadius: BorderRadius.all(Radius.circular(40)),
169 | border: Border.all(color: Colors.grey, width: 1.0),
170 | ),
171 | child: TextField(
172 | controller: _emailController,
173 | decoration: InputDecoration(
174 | border: InputBorder.none,
175 | hintText: "Email Address",
176 | prefixIcon: Icon(Icons.alternate_email),
177 | ),
178 | ),
179 | ),
180 | SizedBox(
181 | height: 20,
182 | ),
183 | Container(
184 | height: 60,
185 | alignment: Alignment.center,
186 | decoration: BoxDecoration(
187 | borderRadius: BorderRadius.all(Radius.circular(40)),
188 | border: Border.all(color: Colors.grey, width: 1.0),
189 | ),
190 | child: TextField(
191 | controller: _passwordController,
192 | obscureText: true,
193 | decoration: InputDecoration(
194 | border: InputBorder.none,
195 | hintText: "Password",
196 | prefixIcon: Icon(Icons.lock_outline),
197 | ),
198 | ),
199 | ),
200 | ],
201 | );
202 | }
203 |
204 | Widget _buttonWidget() {
205 | return InkWell(
206 | onTap: () {
207 | if (isLoginPage == true) {
208 | _submitLogin();
209 | } else {
210 | _submitRegistration();
211 | }
212 | },
213 | child: Container(
214 | margin: EdgeInsets.symmetric(horizontal: 10),
215 | width: widget.sizingInformation.screenSize.width,
216 | alignment: Alignment.center,
217 | padding: EdgeInsets.symmetric(vertical: 14),
218 | decoration: BoxDecoration(
219 | color: Colors.indigo,
220 | borderRadius: BorderRadius.all(Radius.circular(50)),
221 | ),
222 | child: Text(
223 | isLoginPage == true ? "LOGIN" : "REGISTER",
224 | style: TextStyle(fontSize: 18, color: Colors.white),
225 | ),
226 | ),
227 | );
228 | }
229 |
230 | Widget _rowTextWidget() {
231 | return Row(
232 | mainAxisAlignment: MainAxisAlignment.center,
233 | children: [
234 | Text(
235 | isLoginPage == true ? "Don't have account?" : "Have an account?",
236 | style: TextStyle(fontSize: 16, color: Colors.indigo[400]),
237 | ),
238 | InkWell(
239 | onTap: () {
240 | setState(() {
241 | if (isLoginPage == true)
242 | isLoginPage = false;
243 | else
244 | isLoginPage = true;
245 | });
246 | },
247 | child: Text(
248 | isLoginPage == true ? " Sign Up" : " Sign In",
249 | style: TextStyle(
250 | fontSize: 16,
251 | color: Colors.indigo,
252 | fontWeight: FontWeight.bold),
253 | ),
254 | ),
255 | ],
256 | );
257 | }
258 |
259 | void _submitLogin() {
260 | if (_emailController.text.isNotEmpty &&
261 | _passwordController.text.isNotEmpty) {
262 | BlocProvider.of(context).submitLogin(
263 | email: _emailController.text,
264 | password: _passwordController.text,
265 | );
266 | }
267 | }
268 |
269 | void _submitRegistration() {
270 | if (_emailController.text.isNotEmpty &&
271 | _passwordController.text.isNotEmpty &&
272 | _nameController.text.isNotEmpty) {
273 | BlocProvider.of(context).submitRegistration(
274 | email: _emailController.text,
275 | password: _passwordController.text,
276 | name: _nameController.text,
277 | );
278 | }
279 | }
280 | }
281 |
--------------------------------------------------------------------------------
/lib/presentation/pages/widget/message_layout.dart:
--------------------------------------------------------------------------------
1 | import 'package:bubble/bubble.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class MessageLayout extends StatelessWidget {
5 | final String uid;
6 | final String type;
7 | final text;
8 | final time;
9 | final color;
10 | final align;
11 | final boxAlignment;
12 | final nip;
13 | final senderName;
14 | final senderId;
15 | final boxMainAxisAlignment;
16 |
17 | const MessageLayout({
18 | Key key,
19 | this.uid,
20 | this.type,
21 | this.text,
22 | this.time,
23 | this.color,
24 | this.align,
25 | this.boxAlignment,
26 | this.nip,
27 | this.senderName,
28 | this.senderId,
29 | this.boxMainAxisAlignment,
30 | }) : super(key: key);
31 |
32 | @override
33 | Widget build(BuildContext context) {
34 | return Column(
35 | crossAxisAlignment: boxAlignment,
36 | children: [
37 | Row(
38 | crossAxisAlignment: CrossAxisAlignment.start,
39 | mainAxisAlignment: boxMainAxisAlignment,
40 | children: [
41 | color == Colors.blue
42 | ?Container(
43 | height: 55,
44 | width: 55,
45 | decoration: BoxDecoration(
46 | border: Border.all(color: Colors.black,width: 2),
47 | borderRadius: BorderRadius.all(Radius.circular(55))
48 | ),
49 | child: Image.asset("assets/profile_default.png"),
50 | ):Text("",style: TextStyle(fontSize: 0),),
51 | Container(
52 | padding: EdgeInsets.all(8),
53 | margin: EdgeInsets.all(3),
54 | child: Bubble(
55 | color: color,
56 | nip: nip,
57 | child: Column(
58 | crossAxisAlignment: CrossAxisAlignment.start,
59 | children: [
60 | color == Colors.green[300]
61 | ? Text(
62 | "Me",
63 | textAlign: align,
64 | style: TextStyle(
65 | fontSize: 18, fontWeight: FontWeight.bold),
66 | )
67 | : Text(
68 | senderName,
69 | textAlign: align,
70 | style: TextStyle(
71 | fontSize: 18, fontWeight: FontWeight.bold),
72 | ),
73 | ConstrainedBox(
74 | constraints: BoxConstraints(
75 | maxWidth: 400
76 | ),
77 | child: Text(
78 | text==""?"":text,
79 | textAlign: align,
80 | style: TextStyle(fontSize: 18),
81 | ),
82 | ),
83 | Text(
84 | time,
85 | textAlign: align,
86 | style: TextStyle(fontSize: 14),
87 | )
88 | ],
89 | ),
90 | ),
91 | ),
92 | color != Colors.blue
93 | ?Container(
94 | height: 55,
95 | width: 55,
96 | decoration: BoxDecoration(
97 | border: Border.all(color: Colors.black,width: 2),
98 | borderRadius: BorderRadius.all(Radius.circular(55))
99 | ),
100 | child: Image.asset("assets/profile_default.png"),
101 | ):Text("",style: TextStyle(fontSize: 0),),
102 | ],
103 | )
104 | ],
105 | );
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/lib/presentation/screens/home_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:group_chat_room_responsive/presentation/pages/mobile/mobile_page.dart';
3 | import 'package:group_chat_room_responsive/presentation/pages/tablet/tablet_page.dart';
4 | import 'package:group_chat_room_responsive/presentation/pages/web/web_page.dart';
5 | import 'package:responsive_builder/responsive_builder.dart';
6 |
7 | class HomeScreen extends StatelessWidget {
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | return ResponsiveBuilder(
12 | builder: (context,sizingInformation){
13 | if (sizingInformation.isDesktop){
14 | return WebPage(sizingInformation: sizingInformation,);
15 | }
16 | if (sizingInformation.isTablet){
17 | return TabletPage();
18 | }
19 | return MobilePage();
20 | },
21 | );
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/presentation/screens/single_chat_screen.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:group_chat_room_responsive/presentation/pages/mobile/single_chat_page_mobile.dart';
5 | import 'package:group_chat_room_responsive/presentation/pages/tablet/single_chat_page_tablet.dart';
6 | import 'package:group_chat_room_responsive/presentation/pages/web/single_chat_page_web.dart';
7 | import 'package:responsive_builder/responsive_builder.dart';
8 |
9 | class SingleChatScreen extends StatelessWidget {
10 | final String username;
11 | final String uid;
12 |
13 | const SingleChatScreen({Key key, this.username, this.uid}) : super(key: key);
14 | @override
15 | Widget build(BuildContext context) {
16 | return ResponsiveBuilder(
17 | builder: (context,sizingInformation){
18 | if (sizingInformation.isDesktop){
19 | return SingleChatPageWeb(uid: uid,userName: username,);
20 | }
21 | if (sizingInformation.isTablet){
22 | return SingleChatPageTablet(uid: uid,userName: username,);
23 | }
24 | return SingleChatPageMobile(userName: username,uid: uid,);
25 | },
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/presentation/screens/welcome_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:group_chat_room_responsive/presentation/pages/mobile/welcome_page_mobile.dart';
3 | import 'package:group_chat_room_responsive/presentation/pages/tablet/welcome_page_tablet.dart';
4 | import 'package:group_chat_room_responsive/presentation/pages/web/welcome_page_web.dart';
5 | import 'package:responsive_builder/responsive_builder.dart';
6 |
7 | class WelcomeScreen extends StatelessWidget {
8 | final String uid;
9 |
10 | const WelcomeScreen({Key key, this.uid}) : super(key: key);
11 | @override
12 | Widget build(BuildContext context) {
13 | return ResponsiveBuilder(
14 | builder: (context,sizingInformation){
15 | if (sizingInformation.isDesktop){
16 | return WelcomePageWeb(uid: uid,);
17 | }
18 | if (sizingInformation.isTablet){
19 | return WelcomePageTablet(uid: uid,);
20 | }
21 | return WelcomePageMobile(uid: uid,);
22 | },
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | archive:
5 | dependency: transitive
6 | description:
7 | name: archive
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "2.0.13"
11 | args:
12 | dependency: transitive
13 | description:
14 | name: args
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "1.6.0"
18 | async:
19 | dependency: transitive
20 | description:
21 | name: async
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "2.5.0-nullsafety"
25 | bloc:
26 | dependency: transitive
27 | description:
28 | name: bloc
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "6.0.3"
32 | boolean_selector:
33 | dependency: transitive
34 | description:
35 | name: boolean_selector
36 | url: "https://pub.dartlang.org"
37 | source: hosted
38 | version: "2.1.0-nullsafety"
39 | bubble:
40 | dependency: "direct main"
41 | description:
42 | name: bubble
43 | url: "https://pub.dartlang.org"
44 | source: hosted
45 | version: "1.1.9+1"
46 | characters:
47 | dependency: transitive
48 | description:
49 | name: characters
50 | url: "https://pub.dartlang.org"
51 | source: hosted
52 | version: "1.1.0-nullsafety.2"
53 | charcode:
54 | dependency: transitive
55 | description:
56 | name: charcode
57 | url: "https://pub.dartlang.org"
58 | source: hosted
59 | version: "1.2.0-nullsafety"
60 | clock:
61 | dependency: transitive
62 | description:
63 | name: clock
64 | url: "https://pub.dartlang.org"
65 | source: hosted
66 | version: "1.1.0-nullsafety"
67 | cloud_firestore:
68 | dependency: "direct main"
69 | description:
70 | name: cloud_firestore
71 | url: "https://pub.dartlang.org"
72 | source: hosted
73 | version: "0.14.0+2"
74 | cloud_firestore_platform_interface:
75 | dependency: transitive
76 | description:
77 | name: cloud_firestore_platform_interface
78 | url: "https://pub.dartlang.org"
79 | source: hosted
80 | version: "2.0.1"
81 | cloud_firestore_web:
82 | dependency: "direct main"
83 | description:
84 | name: cloud_firestore_web
85 | url: "https://pub.dartlang.org"
86 | source: hosted
87 | version: "0.2.0+1"
88 | collection:
89 | dependency: transitive
90 | description:
91 | name: collection
92 | url: "https://pub.dartlang.org"
93 | source: hosted
94 | version: "1.15.0-nullsafety.2"
95 | convert:
96 | dependency: transitive
97 | description:
98 | name: convert
99 | url: "https://pub.dartlang.org"
100 | source: hosted
101 | version: "2.1.1"
102 | crypto:
103 | dependency: transitive
104 | description:
105 | name: crypto
106 | url: "https://pub.dartlang.org"
107 | source: hosted
108 | version: "2.1.5"
109 | cupertino_icons:
110 | dependency: "direct main"
111 | description:
112 | name: cupertino_icons
113 | url: "https://pub.dartlang.org"
114 | source: hosted
115 | version: "1.0.0"
116 | equatable:
117 | dependency: "direct main"
118 | description:
119 | name: equatable
120 | url: "https://pub.dartlang.org"
121 | source: hosted
122 | version: "1.2.4"
123 | fake_async:
124 | dependency: transitive
125 | description:
126 | name: fake_async
127 | url: "https://pub.dartlang.org"
128 | source: hosted
129 | version: "1.1.0-nullsafety"
130 | firebase:
131 | dependency: transitive
132 | description:
133 | name: firebase
134 | url: "https://pub.dartlang.org"
135 | source: hosted
136 | version: "7.3.0"
137 | firebase_auth:
138 | dependency: "direct main"
139 | description:
140 | name: firebase_auth
141 | url: "https://pub.dartlang.org"
142 | source: hosted
143 | version: "0.18.0+1"
144 | firebase_auth_platform_interface:
145 | dependency: transitive
146 | description:
147 | name: firebase_auth_platform_interface
148 | url: "https://pub.dartlang.org"
149 | source: hosted
150 | version: "2.0.1"
151 | firebase_auth_web:
152 | dependency: "direct main"
153 | description:
154 | name: firebase_auth_web
155 | url: "https://pub.dartlang.org"
156 | source: hosted
157 | version: "0.3.0+1"
158 | firebase_core:
159 | dependency: transitive
160 | description:
161 | name: firebase_core
162 | url: "https://pub.dartlang.org"
163 | source: hosted
164 | version: "0.5.0"
165 | firebase_core_platform_interface:
166 | dependency: transitive
167 | description:
168 | name: firebase_core_platform_interface
169 | url: "https://pub.dartlang.org"
170 | source: hosted
171 | version: "2.0.0"
172 | firebase_core_web:
173 | dependency: transitive
174 | description:
175 | name: firebase_core_web
176 | url: "https://pub.dartlang.org"
177 | source: hosted
178 | version: "0.2.0"
179 | flutter:
180 | dependency: "direct main"
181 | description: flutter
182 | source: sdk
183 | version: "0.0.0"
184 | flutter_bloc:
185 | dependency: "direct main"
186 | description:
187 | name: flutter_bloc
188 | url: "https://pub.dartlang.org"
189 | source: hosted
190 | version: "6.0.5"
191 | flutter_plugin_android_lifecycle:
192 | dependency: transitive
193 | description:
194 | name: flutter_plugin_android_lifecycle
195 | url: "https://pub.dartlang.org"
196 | source: hosted
197 | version: "1.0.8"
198 | flutter_shimmer:
199 | dependency: "direct main"
200 | description:
201 | name: flutter_shimmer
202 | url: "https://pub.dartlang.org"
203 | source: hosted
204 | version: "1.3.0"
205 | flutter_test:
206 | dependency: "direct dev"
207 | description: flutter
208 | source: sdk
209 | version: "0.0.0"
210 | flutter_web_plugins:
211 | dependency: transitive
212 | description: flutter
213 | source: sdk
214 | version: "0.0.0"
215 | font_awesome_flutter:
216 | dependency: "direct main"
217 | description:
218 | name: font_awesome_flutter
219 | url: "https://pub.dartlang.org"
220 | source: hosted
221 | version: "8.8.1"
222 | get_it:
223 | dependency: "direct main"
224 | description:
225 | name: get_it
226 | url: "https://pub.dartlang.org"
227 | source: hosted
228 | version: "4.0.4"
229 | http:
230 | dependency: transitive
231 | description:
232 | name: http
233 | url: "https://pub.dartlang.org"
234 | source: hosted
235 | version: "0.12.2"
236 | http_parser:
237 | dependency: transitive
238 | description:
239 | name: http_parser
240 | url: "https://pub.dartlang.org"
241 | source: hosted
242 | version: "3.1.4"
243 | image_picker:
244 | dependency: "direct main"
245 | description:
246 | name: image_picker
247 | url: "https://pub.dartlang.org"
248 | source: hosted
249 | version: "0.6.7+7"
250 | image_picker_platform_interface:
251 | dependency: transitive
252 | description:
253 | name: image_picker_platform_interface
254 | url: "https://pub.dartlang.org"
255 | source: hosted
256 | version: "1.1.0"
257 | intl:
258 | dependency: "direct main"
259 | description:
260 | name: intl
261 | url: "https://pub.dartlang.org"
262 | source: hosted
263 | version: "0.16.1"
264 | js:
265 | dependency: transitive
266 | description:
267 | name: js
268 | url: "https://pub.dartlang.org"
269 | source: hosted
270 | version: "0.6.2"
271 | logging:
272 | dependency: transitive
273 | description:
274 | name: logging
275 | url: "https://pub.dartlang.org"
276 | source: hosted
277 | version: "0.11.4"
278 | lottie:
279 | dependency: "direct main"
280 | description:
281 | name: lottie
282 | url: "https://pub.dartlang.org"
283 | source: hosted
284 | version: "0.6.0"
285 | matcher:
286 | dependency: transitive
287 | description:
288 | name: matcher
289 | url: "https://pub.dartlang.org"
290 | source: hosted
291 | version: "0.12.10-nullsafety"
292 | meta:
293 | dependency: transitive
294 | description:
295 | name: meta
296 | url: "https://pub.dartlang.org"
297 | source: hosted
298 | version: "1.3.0-nullsafety.2"
299 | nested:
300 | dependency: transitive
301 | description:
302 | name: nested
303 | url: "https://pub.dartlang.org"
304 | source: hosted
305 | version: "0.0.4"
306 | path:
307 | dependency: transitive
308 | description:
309 | name: path
310 | url: "https://pub.dartlang.org"
311 | source: hosted
312 | version: "1.8.0-nullsafety"
313 | pedantic:
314 | dependency: transitive
315 | description:
316 | name: pedantic
317 | url: "https://pub.dartlang.org"
318 | source: hosted
319 | version: "1.9.2"
320 | plugin_platform_interface:
321 | dependency: transitive
322 | description:
323 | name: plugin_platform_interface
324 | url: "https://pub.dartlang.org"
325 | source: hosted
326 | version: "1.0.2"
327 | provider:
328 | dependency: transitive
329 | description:
330 | name: provider
331 | url: "https://pub.dartlang.org"
332 | source: hosted
333 | version: "4.3.2+2"
334 | quiver:
335 | dependency: transitive
336 | description:
337 | name: quiver
338 | url: "https://pub.dartlang.org"
339 | source: hosted
340 | version: "2.1.3"
341 | responsive_builder:
342 | dependency: "direct main"
343 | description:
344 | name: responsive_builder
345 | url: "https://pub.dartlang.org"
346 | source: hosted
347 | version: "0.3.0"
348 | sky_engine:
349 | dependency: transitive
350 | description: flutter
351 | source: sdk
352 | version: "0.0.99"
353 | source_span:
354 | dependency: transitive
355 | description:
356 | name: source_span
357 | url: "https://pub.dartlang.org"
358 | source: hosted
359 | version: "1.8.0-nullsafety"
360 | stack_trace:
361 | dependency: transitive
362 | description:
363 | name: stack_trace
364 | url: "https://pub.dartlang.org"
365 | source: hosted
366 | version: "1.10.0-nullsafety"
367 | stream_channel:
368 | dependency: transitive
369 | description:
370 | name: stream_channel
371 | url: "https://pub.dartlang.org"
372 | source: hosted
373 | version: "2.1.0-nullsafety"
374 | string_scanner:
375 | dependency: transitive
376 | description:
377 | name: string_scanner
378 | url: "https://pub.dartlang.org"
379 | source: hosted
380 | version: "1.1.0-nullsafety"
381 | term_glyph:
382 | dependency: transitive
383 | description:
384 | name: term_glyph
385 | url: "https://pub.dartlang.org"
386 | source: hosted
387 | version: "1.2.0-nullsafety"
388 | test_api:
389 | dependency: transitive
390 | description:
391 | name: test_api
392 | url: "https://pub.dartlang.org"
393 | source: hosted
394 | version: "0.2.19-nullsafety"
395 | typed_data:
396 | dependency: transitive
397 | description:
398 | name: typed_data
399 | url: "https://pub.dartlang.org"
400 | source: hosted
401 | version: "1.3.0-nullsafety.2"
402 | vector_math:
403 | dependency: transitive
404 | description:
405 | name: vector_math
406 | url: "https://pub.dartlang.org"
407 | source: hosted
408 | version: "2.1.0-nullsafety.2"
409 | sdks:
410 | dart: ">=2.10.0-0.0.dev <2.10.0"
411 | flutter: ">=1.16.0 <2.0.0"
412 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: group_chat_room_responsive
2 | description: A new Flutter application.
3 |
4 | # The following line prevents the package from being accidentally published to
5 | # pub.dev using `pub publish`. This is preferred for private packages.
6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev
7 |
8 | # The following defines the version and build number for your application.
9 | # A version number is three numbers separated by dots, like 1.2.43
10 | # followed by an optional build number separated by a +.
11 | # Both the version and the builder number may be overridden in flutter
12 | # build by specifying --build-name and --build-number, respectively.
13 | # In Android, build-name is used as versionName while build-number used as versionCode.
14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
16 | # Read more about iOS versioning at
17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
18 | version: 1.0.0+1
19 |
20 | environment:
21 | sdk: ">=2.7.0 <3.0.0"
22 |
23 | dependencies:
24 | flutter:
25 | sdk: flutter
26 | responsive_builder: ^0.3.0
27 | font_awesome_flutter: ^8.8.1
28 | #message shape bubble
29 | bubble: ^1.1.9+1
30 | #state management
31 | flutter_bloc: ^6.0.5
32 | equatable: ^1.2.4
33 | #dateFormat
34 | intl: ^0.16.1
35 | #image picker
36 | image_picker: ^0.6.7+7
37 | #firebase
38 | cloud_firestore: ^0.14.0+2
39 | firebase_auth: ^0.18.0+1
40 | firebase_auth_web: ^0.3.0+1
41 | cloud_firestore_web: ^0.2.0+1
42 | lottie: ^0.6.0
43 | get_it: ^4.0.4
44 | flutter_shimmer: ^1.3.0
45 |
46 | # The following adds the Cupertino Icons font to your application.
47 | # Use with the CupertinoIcons class for iOS style icons.
48 | cupertino_icons: ^1.0.0
49 |
50 | dev_dependencies:
51 | flutter_test:
52 | sdk: flutter
53 |
54 | # For information on the generic Dart part of this file, see the
55 | # following page: https://dart.dev/tools/pub/pubspec
56 |
57 | # The following section is specific to Flutter.
58 | flutter:
59 |
60 | # The following line ensures that the Material Icons font is
61 | # included with your application, so that you can use the icons in
62 | # the material Icons class.
63 | uses-material-design: true
64 |
65 | # To add assets to your application, add an assets section, like this:
66 | assets:
67 | - assets/.
68 |
69 | # An image asset can refer to one or more resolution-specific "variants", see
70 | # https://flutter.dev/assets-and-images/#resolution-aware.
71 |
72 | # For details regarding adding assets from package dependencies, see
73 | # https://flutter.dev/assets-and-images/#from-packages
74 |
75 | # To add custom fonts to your application, add a fonts section here,
76 | # in this "flutter" section. Each entry in this list should have a
77 | # "family" key with the font family name, and a "fonts" key with a
78 | # list giving the asset and other descriptors for the font. For
79 | # example:
80 | # fonts:
81 | # - family: Schyler
82 | # fonts:
83 | # - asset: fonts/Schyler-Regular.ttf
84 | # - asset: fonts/Schyler-Italic.ttf
85 | # style: italic
86 | # - family: Trajan Pro
87 | # fonts:
88 | # - asset: fonts/TrajanPro.ttf
89 | # - asset: fonts/TrajanPro_Bold.ttf
90 | # weight: 700
91 | #
92 | # For details regarding fonts from package dependencies,
93 | # see https://flutter.dev/custom-fonts/#from-packages
94 |
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_test/flutter_test.dart';
10 |
11 | import 'package:group_chat_room_responsive/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(MyApp());
17 |
18 | // Verify that our counter starts at 0.
19 | expect(find.text('0'), findsOneWidget);
20 | expect(find.text('1'), findsNothing);
21 |
22 | // Tap the '+' icon and trigger a frame.
23 | await tester.tap(find.byIcon(Icons.add));
24 | await tester.pump();
25 |
26 | // Verify that our counter has incremented.
27 | expect(find.text('0'), findsNothing);
28 | expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/web/favicon.png
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirk3321/group_chat_room_responsive/e6ef8e99e2b46d36bc1247ba4863d6cf3d438e15/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | group_chat_room_responsive
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
41 |
44 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "group_chat_room_responsive",
3 | "short_name": "group_chat_room_responsive",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "A new Flutter application.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------