├── README.md ├── ios ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── 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-1024x1024@1x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist └── .gitignore ├── .gitattributes ├── AppIcons ├── appstore.png ├── playstore.png ├── android │ ├── 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 └── Assets.xcassets │ └── AppIcon.appiconset │ ├── 100.png │ ├── 114.png │ ├── 120.png │ ├── 128.png │ ├── 144.png │ ├── 152.png │ ├── 16.png │ ├── 167.png │ ├── 172.png │ ├── 180.png │ ├── 196.png │ ├── 20.png │ ├── 216.png │ ├── 256.png │ ├── 29.png │ ├── 32.png │ ├── 40.png │ ├── 48.png │ ├── 50.png │ ├── 512.png │ ├── 55.png │ ├── 57.png │ ├── 58.png │ ├── 60.png │ ├── 64.png │ ├── 72.png │ ├── 76.png │ ├── 80.png │ ├── 87.png │ ├── 88.png │ ├── 1024.png │ └── Contents.json ├── assets └── images │ ├── email.png │ ├── logo.jpeg │ ├── MaskGroup1.png │ ├── logIn.svg │ ├── logOut.svg │ └── signUp.svg ├── lib ├── Utils │ ├── palette.dart │ ├── consts.dart │ └── commonWidgets.dart ├── tools │ ├── custom_toast.dart │ └── loading.dart ├── Screens │ ├── webview.dart │ ├── credentials │ │ ├── loginRelated │ │ │ ├── forget_password_page.dart │ │ │ └── login_page.dart │ │ └── signUpRelated │ │ │ └── signup_page.dart │ ├── Admin │ │ ├── allUsers.dart │ │ └── commentsNChatAdmin.dart │ └── user_info.dart ├── Models │ ├── announcements_model.dart │ └── users.dart ├── Services │ ├── firebase_api.dart │ ├── user_state.dart │ ├── global_method.dart │ ├── notificationHandler.dart │ ├── payment.dart │ └── authentication_service.dart ├── main.dart ├── Database │ └── database.dart └── announcements │ ├── announcements.dart │ └── addAnnouncements.dart ├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── 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 │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── values-night │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── bull_signal │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── google-services.json │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle └── build.gradle ├── .metadata ├── .gitignore ├── LICENSE ├── test └── widget_test.dart ├── analysis_options.yaml ├── pubspec.yaml └── pubspec.lock /README.md: -------------------------------------------------------------------------------- 1 | # bull_signal 2 | 3 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /AppIcons/appstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/appstore.png -------------------------------------------------------------------------------- /AppIcons/playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/playstore.png -------------------------------------------------------------------------------- /assets/images/email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/assets/images/email.png -------------------------------------------------------------------------------- /assets/images/logo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/assets/images/logo.jpeg -------------------------------------------------------------------------------- /lib/Utils/palette.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | Color containerColor = Colors.green; 4 | -------------------------------------------------------------------------------- /assets/images/MaskGroup1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/assets/images/MaskGroup1.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /AppIcons/android/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/android/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /AppIcons/android/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/android/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /AppIcons/android/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/android/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AppIcons/android/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/android/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AppIcons/android/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/android/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/100.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/114.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/120.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/128.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/144.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/152.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/16.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/167.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/172.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/172.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/180.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/196.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/196.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/20.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/216.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/216.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/256.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/29.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/32.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/40.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/48.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/50.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/512.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/55.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/57.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/58.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/60.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/64.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/72.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/76.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/80.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/87.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/88.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/88.png -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/AppIcons/Assets.xcassets/AppIcon.appiconset/1024.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/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/hassan-zafar/bull_signal/HEAD/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/hassan-zafar/bull_signal/HEAD/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/hassan-zafar/bull_signal/HEAD/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/hassan-zafar/bull_signal/HEAD/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/hassan-zafar/bull_signal/HEAD/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/hassan-zafar/bull_signal/HEAD/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/hassan-zafar/bull_signal/HEAD/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/hassan-zafar/bull_signal/HEAD/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/hassan-zafar/bull_signal/HEAD/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/hassan-zafar/bull_signal/HEAD/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/hassan-zafar/bull_signal/HEAD/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/hassan-zafar/bull_signal/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hassan-zafar/bull_signal/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/bull_signal/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.hassan.bull_signal 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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-6.7-all.zip 7 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.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/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.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: cf4400006550b70f28e4b4af815151d1e74846c6 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /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 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/tools/custom_toast.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fluttertoast/fluttertoast.dart'; 3 | 4 | void successToast({ 5 | required String message, 6 | int duration = 3, 7 | }) { 8 | Fluttertoast.showToast( 9 | msg: message, 10 | ); 11 | } 12 | 13 | void showToast({ 14 | required String message, 15 | int duration = 3, 16 | }) { 17 | Fluttertoast.showToast( 18 | msg: message, 19 | ); 20 | } 21 | 22 | void errorToast({ 23 | required String message, 24 | int duration = 4, 25 | }) { 26 | Fluttertoast.showToast(msg: message, backgroundColor: Colors.red); 27 | } 28 | -------------------------------------------------------------------------------- /lib/tools/loading.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class LoadingIndicator extends StatelessWidget { 7 | const LoadingIndicator({Key? key}) : super(key: key); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | final widget = (Platform.isAndroid) 12 | ? const CircularProgressIndicator( 13 | backgroundColor: Colors.black, 14 | ) 15 | : const CupertinoActivityIndicator(); 16 | return Container( 17 | alignment: Alignment.center, 18 | child: widget, 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /lib/Screens/webview.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; 3 | 4 | class Webview extends StatefulWidget { 5 | const Webview({Key? key}) : super(key: key); 6 | 7 | @override 8 | _WebviewState createState() => _WebviewState(); 9 | } 10 | 11 | class _WebviewState extends State { 12 | @override 13 | Widget build(BuildContext context) { 14 | return const WebviewScaffold( 15 | withZoom: true, 16 | url: "https://www.tradingview.com/markets/cryptocurrencies/prices-all/", 17 | withJavascript: true, 18 | // appBar: AppBar( 19 | // title: Text("hjg"), 20 | // backgroundColor: Colors.black, 21 | // ), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.5.0' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | classpath 'com.google.gms:google-services:4.3.10' 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | google() 18 | mavenCentral() 19 | } 20 | } 21 | 22 | rootProject.buildDir = '../build' 23 | subprojects { 24 | project.buildDir = "${rootProject.buildDir}/${project.name}" 25 | 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 9.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /.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 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lib/Models/announcements_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | 3 | class AnnouncementsModel { 4 | final String? userId; 5 | final String? announcementId; 6 | final String? announcementTitle; 7 | final String? description; 8 | final Timestamp? timestamp; 9 | final String? token; 10 | final String? imageUrl; 11 | 12 | AnnouncementsModel({ 13 | this.userId, 14 | this.announcementId, 15 | this.announcementTitle, 16 | this.description, 17 | this.timestamp, 18 | this.token, 19 | this.imageUrl, 20 | }); 21 | 22 | Map toMap() { 23 | return {}; 24 | } 25 | 26 | factory AnnouncementsModel.fromDocument(doc) { 27 | return AnnouncementsModel( 28 | userId: doc.data()["userId"], 29 | announcementId: doc.data()["announcementId"], 30 | announcementTitle: doc.data()["announcementTitle"], 31 | description: doc.data()["description"], 32 | timestamp: doc.data()["timestamp"], 33 | token: doc.data()["token"], 34 | imageUrl: doc.data()["imageUrl"], 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Hassan Ayoub Zafar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /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:bull_signal/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(const 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 | -------------------------------------------------------------------------------- /lib/Utils/consts.dart: -------------------------------------------------------------------------------- 1 | import 'package:bull_signal/Models/users.dart'; 2 | import 'package:cloud_firestore/cloud_firestore.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | final userRef = FirebaseFirestore.instance.collection('users'); 6 | final announcementsRef = FirebaseFirestore.instance.collection('announcements'); 7 | final commentsRef = FirebaseFirestore.instance.collection('comments'); 8 | final chatRoomRef = FirebaseFirestore.instance.collection('chatRoom'); 9 | final chatListRef = FirebaseFirestore.instance.collection('chatLists'); 10 | 11 | const String logo = 'assets/images/logo.jpeg'; 12 | // const String logout = 'assets/images/logOut.svg'; 13 | 14 | // const String loginIcon = 'assets/images/logIn.svg'; 15 | // const String signUp = 'assets/images/signUp.svg'; 16 | AppUserModel? currentUser; 17 | String? uid; 18 | 19 | TextStyle titleTextStyle({double fontSize = 25, Color? color = Colors.white}) { 20 | return TextStyle( 21 | fontSize: fontSize, 22 | fontWeight: FontWeight.w600, 23 | color: color, 24 | letterSpacing: 1.8); 25 | } 26 | 27 | TextStyle customTextStyle( 28 | {FontWeight fontWeight = FontWeight.w300, 29 | double fontSize = 25, 30 | Color color = Colors.white}) { 31 | return TextStyle( 32 | fontSize: fontSize, 33 | fontWeight: fontWeight, 34 | color: color, 35 | letterSpacing: 3); 36 | } 37 | -------------------------------------------------------------------------------- /lib/Services/firebase_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:bull_signal/Models/announcements_model.dart'; 2 | import 'package:bull_signal/Utils/consts.dart'; 3 | import 'package:cloud_firestore/cloud_firestore.dart'; 4 | 5 | class FirebaseApi { 6 | addAnnouncements( 7 | {required final String postId, 8 | required final String announcementTitle, 9 | required final String imageUrl, 10 | // required final String eachUserId, 11 | required String eachUserToken, 12 | required final String description}) async { 13 | FirebaseFirestore.instance 14 | .collection("announcements") 15 | // .doc(eachUserId) 16 | // .collection("userAnnouncements") 17 | .doc(postId) 18 | .set({ 19 | "announcementId": postId, 20 | "announcementTitle": announcementTitle, 21 | "description": description, 22 | "timestamp": DateTime.now(), 23 | "token": eachUserToken, 24 | "imageUrl": imageUrl, 25 | "userId": currentUser!.id 26 | }); 27 | } 28 | 29 | Future getAnnouncements() async { 30 | List tempAllAnnouncements = []; 31 | QuerySnapshot tempAnnouncementsSnapshot = 32 | await FirebaseFirestore.instance.collection('announcements').get(); 33 | 34 | tempAnnouncementsSnapshot.docs.forEach((element) { 35 | tempAllAnnouncements.add(AnnouncementsModel.fromDocument(element)); 36 | }); 37 | return tempAllAnnouncements; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /android/app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "127968863702", 4 | "project_id": "bull-signal-c3a7a", 5 | "storage_bucket": "bull-signal-c3a7a.appspot.com" 6 | }, 7 | "client": [ 8 | { 9 | "client_info": { 10 | "mobilesdk_app_id": "1:127968863702:android:ff99e83a9147b50a853077", 11 | "android_client_info": { 12 | "package_name": "com.hassan.bull_signal" 13 | } 14 | }, 15 | "oauth_client": [ 16 | { 17 | "client_id": "127968863702-e4360f1k2leeccaabcdi00qa644a153e.apps.googleusercontent.com", 18 | "client_type": 1, 19 | "android_info": { 20 | "package_name": "com.hassan.bull_signal", 21 | "certificate_hash": "387accc7b18bc054a3d2c235d89180c8014d7a46" 22 | } 23 | }, 24 | { 25 | "client_id": "127968863702-mitbhcmh8e3a1r042btl5vtoards0aqg.apps.googleusercontent.com", 26 | "client_type": 3 27 | } 28 | ], 29 | "api_key": [ 30 | { 31 | "current_key": "AIzaSyAUOklz64K8JIi-Qf6Yz95F77wrVg1buDA" 32 | } 33 | ], 34 | "services": { 35 | "appinvite_service": { 36 | "other_platform_oauth_client": [ 37 | { 38 | "client_id": "127968863702-mitbhcmh8e3a1r042btl5vtoards0aqg.apps.googleusercontent.com", 39 | "client_type": 3 40 | } 41 | ] 42 | } 43 | } 44 | } 45 | ], 46 | "configuration_version": "1" 47 | } -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /assets/images/logIn.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Bull Signal 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | bull_signal 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UIViewControllerBasedStatusBarAppearance 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /assets/images/logOut.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:bull_signal/Screens/webview.dart'; 2 | import 'package:bull_signal/Services/user_state.dart'; 3 | import 'package:bull_signal/announcements/announcements.dart'; 4 | import 'package:firebase_core/firebase_core.dart'; 5 | import 'package:firebase_messaging/firebase_messaging.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:flutter_local_notifications/flutter_local_notifications.dart'; 8 | import 'package:get_storage/get_storage.dart'; 9 | import 'package:get/get.dart'; 10 | 11 | const AndroidNotificationChannel channel = AndroidNotificationChannel( 12 | "high_importance_channel", 13 | "High Importance Notifications", 14 | importance: Importance.high, 15 | playSound: true, 16 | ); 17 | 18 | final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = 19 | FlutterLocalNotificationsPlugin(); 20 | 21 | Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { 22 | await Firebase.initializeApp(); 23 | } 24 | 25 | Future main() async { 26 | await GetStorage.init(); 27 | await Firebase.initializeApp(); 28 | FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); 29 | await flutterLocalNotificationsPlugin 30 | .resolvePlatformSpecificImplementation< 31 | AndroidFlutterLocalNotificationsPlugin>() 32 | ?.createNotificationChannel(channel); 33 | 34 | await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( 35 | alert: true, 36 | badge: true, 37 | sound: true, 38 | ); 39 | 40 | runApp(const MyApp()); 41 | } 42 | 43 | class MyApp extends StatelessWidget { 44 | const MyApp({Key? key}) : super(key: key); 45 | 46 | // This widget is the root of your application. 47 | @override 48 | Widget build(BuildContext context) { 49 | return GetMaterialApp( 50 | title: 'Bull Signal', 51 | theme: ThemeData( 52 | appBarTheme: const AppBarTheme(backgroundColor: Colors.transparent), 53 | // primarySwatch: Colors.accents, 54 | brightness: Brightness.dark), 55 | home: const UserState(), 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/Database/database.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:bull_signal/Models/users.dart'; 4 | import 'package:bull_signal/Utils/consts.dart'; 5 | import 'package:bull_signal/tools/custom_toast.dart'; 6 | import 'package:cloud_firestore/cloud_firestore.dart'; 7 | import 'package:firebase_messaging/firebase_messaging.dart'; 8 | 9 | class DatabaseMethods { 10 | addUserInfoToFirebase({ 11 | required final String password, 12 | required final String? name, 13 | required final String? joinedAt, 14 | required final String? phoneNo, 15 | required final String? imageUrl, 16 | required final Timestamp? createdAt, 17 | required final String email, 18 | required final String userId, 19 | final bool? isAdmin, 20 | }) { 21 | print("addUserInfoToFirebase"); 22 | return userRef.doc(userId).set({ 23 | 'id': userId, 24 | 'name': name, 25 | 'phoneNo': phoneNo, 26 | 'password': password, 27 | 'createdAt': createdAt, 28 | 'isAdmin': isAdmin, 29 | 'email': email, 30 | 'joinedAt': joinedAt, 31 | 'imageUrl': imageUrl, 32 | 'androidNotificationToken': "", 33 | }).then((value) async { 34 | final DocumentSnapshot _user = await userRef.doc(uid).get(); 35 | currentUser = AppUserModel.fromDocument(_user); 36 | // currentUser = userModel; 37 | }).catchError( 38 | (Object obj) { 39 | errorToast(message: obj.toString()); 40 | }, 41 | ); 42 | } 43 | 44 | Future fetchUserInfoFromFirebase({ 45 | required String uid, 46 | }) async { 47 | final DocumentSnapshot _user = await userRef.doc(uid).get(); 48 | currentUser = AppUserModel.fromDocument(_user); 49 | createToken(uid); 50 | Map userData = json.decode(currentUser!.toJson()); 51 | // UserLocalData().setUserModel(json.encode(userData)); 52 | // print(user); 53 | print(currentUser!.email); 54 | } 55 | 56 | createToken(String uid) { 57 | FirebaseMessaging.instance.getToken().then((token) { 58 | userRef.doc(uid).update({ 59 | "androidNotificationToken": token, 60 | }); 61 | // UserLocalData().setToken(token!); 62 | }); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/Models/users.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | class AppUserModel { 4 | final String? id; 5 | final String? name; 6 | final String? phoneNo; 7 | final String? password; 8 | final String? timestamp; 9 | final String? imageUrl; 10 | final bool? isAdmin; 11 | final String? email; 12 | final String? androidNotificationToken; 13 | final String? subscriptionEndTIme; 14 | 15 | // final Map? sectionsAppointed; 16 | AppUserModel( 17 | {this.id, 18 | this.name, 19 | this.phoneNo, 20 | this.password, 21 | this.imageUrl, 22 | this.timestamp, 23 | this.isAdmin, 24 | this.subscriptionEndTIme, 25 | this.email, 26 | this.androidNotificationToken}); 27 | 28 | Map toMap() { 29 | return { 30 | 'id': id, 31 | 'name': name, 32 | 'phoneNo': phoneNo, 33 | 'password': password, 34 | 'imageUrl': imageUrl, 35 | 'timestamp': timestamp, 36 | 'subscriptionEndTIme': subscriptionEndTIme, 37 | 'isAdmin': isAdmin, 38 | 'email': email, 39 | 'androidNotificationToken': androidNotificationToken, 40 | }; 41 | } 42 | 43 | factory AppUserModel.fromMap(Map map) { 44 | return AppUserModel( 45 | id: map['id'], 46 | name: map['name'], 47 | phoneNo: map['phoneNo'], 48 | password: map['password'], 49 | timestamp: map['timestamp'], 50 | imageUrl: map['imageUrl'], 51 | isAdmin: map['isAdmin'], 52 | subscriptionEndTIme: map['subscriptionEndTIme'], 53 | email: map['email'], 54 | androidNotificationToken: map['androidNotificationToken']); 55 | } 56 | 57 | factory AppUserModel.fromDocument(doc) { 58 | return AppUserModel( 59 | id: doc.data()["id"], 60 | password: doc.data()["password"], 61 | name: doc.data()["name"], 62 | timestamp: doc.data()["timestamp"], 63 | imageUrl: doc.data()["imageUrl"], 64 | email: doc.data()["email"], 65 | isAdmin: doc.data()["isAdmin"], 66 | subscriptionEndTIme: doc.data()["subscriptionEndTIme"], 67 | phoneNo: doc.data()["phoneNo"], 68 | androidNotificationToken: doc.data()["androidNotificationToken"], 69 | ); 70 | } 71 | 72 | String toJson() => json.encode(toMap()); 73 | 74 | factory AppUserModel.fromJson(String source) => 75 | AppUserModel.fromMap(json.decode(source)); 76 | } 77 | -------------------------------------------------------------------------------- /lib/Services/user_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:bull_signal/Database/database.dart'; 2 | import 'package:bull_signal/Screens/credentials/loginRelated/login_page.dart'; 3 | import 'package:bull_signal/Utils/consts.dart'; 4 | import 'package:bull_signal/announcements/announcements.dart'; 5 | import 'package:bull_signal/tools/loading.dart'; 6 | import 'package:firebase_auth/firebase_auth.dart'; 7 | import 'package:flutter/material.dart'; 8 | 9 | class UserState extends StatefulWidget { 10 | const UserState({Key? key}) : super(key: key); 11 | 12 | @override 13 | State createState() => _UserStateState(); 14 | } 15 | 16 | class _UserStateState extends State { 17 | bool isLogged = false; 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return StreamBuilder( 22 | stream: FirebaseAuth.instance.authStateChanges(), 23 | // ignore: missing_return 24 | builder: (context, AsyncSnapshot userSnapshot) { 25 | if (userSnapshot.connectionState == ConnectionState.waiting) { 26 | return const Center( 27 | child: CircularProgressIndicator(), 28 | ); 29 | } else if (userSnapshot.connectionState == ConnectionState.active) { 30 | if (userSnapshot.hasData) { 31 | print('userSnapshot.hasData ${userSnapshot.hasData}'); 32 | uid = userSnapshot.data!.uid; 33 | DatabaseMethods() 34 | .fetchUserInfoFromFirebase(uid: userSnapshot.data!.uid) 35 | .then((value) { 36 | print('The user is already logged in'); 37 | // if (mounted) { 38 | // setState(() { 39 | // isLogged = true; 40 | // }); 41 | // } 42 | // print(isLogged); 43 | }); 44 | return Announcements(); 45 | // MainScreens(); 46 | } else { 47 | print('The user didn\'t login yet'); 48 | return 49 | // IntroductionAuthScreen(); 50 | LoginPage(); 51 | } 52 | } else if (userSnapshot.hasError) { 53 | return const Center( 54 | child: Text('Error occured'), 55 | ); 56 | } else { 57 | return const Center( 58 | child: Text('Error occured'), 59 | ); 60 | } 61 | }); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /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.google.gms.google-services' 25 | apply plugin: 'com.android.application' 26 | apply plugin: 'kotlin-android' 27 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 28 | 29 | android { 30 | compileSdkVersion flutter.compileSdkVersion 31 | 32 | compileOptions { 33 | sourceCompatibility JavaVersion.VERSION_1_8 34 | targetCompatibility JavaVersion.VERSION_1_8 35 | } 36 | 37 | kotlinOptions { 38 | jvmTarget = '1.8' 39 | } 40 | 41 | sourceSets { 42 | main.java.srcDirs += 'src/main/kotlin' 43 | } 44 | 45 | defaultConfig { 46 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 47 | applicationId "com.hassan.bull_signal" 48 | minSdkVersion 21 49 | targetSdkVersion flutter.targetSdkVersion 50 | versionCode flutterVersionCode.toInteger() 51 | versionName flutterVersionName 52 | } 53 | 54 | buildTypes { 55 | release { 56 | crunchPngs false // or true 57 | 58 | // TODO: Add your own signing config for the release build. 59 | // Signing with the debug keys for now, so `flutter run --release` works. 60 | signingConfig signingConfigs.debug 61 | } 62 | } 63 | } 64 | 65 | flutter { 66 | source '../..' 67 | } 68 | 69 | dependencies { 70 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 71 | implementation platform('com.google.firebase:firebase-bom:29.0.4') 72 | implementation 'com.google.firebase:firebase-analytics-ktx' 73 | } 74 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/Services/global_method.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class GlobalMethods { 4 | Future showDialogg( 5 | String title, String subtitle, Function fct, BuildContext context) async { 6 | showDialog( 7 | context: context, 8 | builder: (BuildContext ctx) { 9 | return AlertDialog( 10 | title: Row( 11 | children: [ 12 | Padding( 13 | padding: const EdgeInsets.only(right: 6.0), 14 | child: Image.network( 15 | 'https://image.flaticon.com/icons/png/128/564/564619.png', 16 | height: 20, 17 | width: 20, 18 | ), 19 | ), 20 | Padding( 21 | padding: const EdgeInsets.all(8.0), 22 | child: Text(title), 23 | ), 24 | ], 25 | ), 26 | content: Text(subtitle), 27 | actions: [ 28 | TextButton( 29 | onPressed: () => Navigator.pop(context), 30 | child: Text('Cancel')), 31 | TextButton( 32 | onPressed: () { 33 | fct(); 34 | Navigator.pop(context); 35 | }, 36 | child: Text('ok')) 37 | ], 38 | ); 39 | }); 40 | } 41 | 42 | Future authErrorHandle(String subtitle, BuildContext context) async { 43 | showDialog( 44 | context: context, 45 | builder: (BuildContext ctx) { 46 | return AlertDialog( 47 | title: Row( 48 | children: [ 49 | Padding( 50 | padding: const EdgeInsets.only(right: 6.0), 51 | child: Image.network( 52 | 'https://image.flaticon.com/icons/png/128/564/564619.png', 53 | height: 20, 54 | width: 20, 55 | ), 56 | ), 57 | Padding( 58 | padding: const EdgeInsets.all(8.0), 59 | child: Text('Error occured'), 60 | ), 61 | ], 62 | ), 63 | content: Text(subtitle), 64 | actions: [ 65 | 66 | TextButton( 67 | onPressed: () { 68 | Navigator.pop(context); 69 | }, 70 | child: Text('Ok')) 71 | ], 72 | ); 73 | }); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/Services/notificationHandler.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:convert'; 3 | import 'package:flutter_local_notifications/flutter_local_notifications.dart'; 4 | import 'package:firebase_messaging/firebase_messaging.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:http/http.dart' as http; 7 | 8 | import '../main.dart'; 9 | 10 | Future?> sendAndRetrieveMessage( 11 | {required String token, 12 | required String message, 13 | required BuildContext context, 14 | String? imageUrl, 15 | required String title}) async { 16 | final String serverToken = 17 | "AAAAHcuJ5dY:APA91bEnnYQLBQ3Co7adJa3RlxPkg8LsuF9ySk8VOzfg3ETHouXtysJmlNzkniGQNiBVjNTcoLJCK3Z2cINUcsww8HxfI82NB-BibVTr02lUPpChs-uePcWdifqH44OA5r4BGJ4BjGaF"; 18 | final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance; 19 | 20 | await http 21 | .post( 22 | Uri.parse('https://fcm.googleapis.com/fcm/send'), 23 | headers: { 24 | 'Content-Type': 'application/json', 25 | 'Authorization': 'key=$serverToken', 26 | }, 27 | body: jsonEncode( 28 | { 29 | 'notification': { 30 | 'body': message, 31 | 'title': '$title', 32 | imageUrl == null ? "" : "image": imageUrl 33 | }, 34 | 'priority': 'high', 35 | 'data': { 36 | 'click_action': 'FLUTTER_NOTIFICATION_CLICK', 37 | 'id': '1', 38 | 'status': 'done' 39 | }, 40 | 'to': token, 41 | }, 42 | ), 43 | ) 44 | .then((value) => print("Notification Sent")); 45 | FirebaseMessaging.onMessage.listen((RemoteMessage message) { 46 | RemoteNotification? notification = message.notification; 47 | AndroidNotification? android = message.notification?.android; 48 | if (notification != null && android != null) { 49 | flutterLocalNotificationsPlugin.show( 50 | notification.hashCode, 51 | notification.title, 52 | notification.body, 53 | NotificationDetails( 54 | android: AndroidNotificationDetails( 55 | channel.id, 56 | channel.name, 57 | // channel.description, 58 | color: Colors.blue, 59 | playSound: true, 60 | icon: '@mipmap/ic_launcher', 61 | ), 62 | )); 63 | } 64 | }); 65 | FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { 66 | RemoteNotification? notification = message.notification; 67 | AndroidNotification? android = message.notification?.android; 68 | if (notification != null && android != null) { 69 | showDialog( 70 | context: context, 71 | builder: (_) { 72 | return AlertDialog( 73 | title: Text(notification.title!), 74 | content: SingleChildScrollView( 75 | child: Column( 76 | crossAxisAlignment: CrossAxisAlignment.start, 77 | children: [Text(notification.body!)], 78 | ), 79 | ), 80 | ); 81 | }); 82 | } 83 | }); 84 | return null; 85 | } 86 | -------------------------------------------------------------------------------- /lib/Services/payment.dart: -------------------------------------------------------------------------------- 1 | // import 'dart:convert'; 2 | 3 | // import 'package:flutter/services.dart'; 4 | // import 'package:http/http.dart' as http; 5 | // import 'package:stripe_payment/stripe_payment.dart'; 6 | 7 | // class StripeTransactionResponse { 8 | // String message; 9 | // bool success; 10 | // StripeTransactionResponse({this.message, this.success}); 11 | // } 12 | 13 | // class StripeService { 14 | // static String apiBase = 'https://api.stripe.com/v1'; 15 | // static String paymentApiUrl = '${StripeService.apiBase}/payment_intents'; 16 | // static Uri paymentApiUri = Uri.parse(paymentApiUrl); 17 | // static String secret = 18 | // 'sk_test_51HEKkjIEmWkp6b7SkKDMW5Z66ibqf7Lwu09L9e9jydsxf16FNAaDeYncbxjB5M20dfQc46MeO3Rmf2HQZ25WVzw400FuIAF6cR'; 19 | 20 | // static Map headers = { 21 | // 'Authorization': 'Bearer ${StripeService.secret}', 22 | // 'Content-type': 'application/x-www-form-urlencoded' 23 | // }; 24 | 25 | // static init() { 26 | // StripePayment.setOptions(StripeOptions( 27 | // publishableKey: 28 | // 'pk_test_51HEKkjIEmWkp6b7ScGJgzPctYP1DknJpw4c8ikwLRdBiDgZPHkq0GnGsNnSnqNtFlngW1oJftKzopNdMVqmUsaWb00J1DNBegr', 29 | // merchantId: 'test', 30 | // androidPayMode: 'test')); 31 | // } 32 | 33 | // static Future> createPaymentIntent( 34 | // String amount, String currency) async { 35 | // try { 36 | // Map body = {"amount": amount, "currency": currency}; 37 | // var response = 38 | // await http.post(paymentApiUri, headers: headers, body: body); 39 | // return jsonDecode(response.body); 40 | // } catch (error) { 41 | // print('error occured in the payment intent $error '); 42 | // } 43 | // return null; 44 | // } 45 | 46 | // static Future payWithNewCard( 47 | // {String amount, String currency}) async { 48 | // try { 49 | // var paymentMethod = await StripePayment.paymentRequestWithCardForm( 50 | // CardFormPaymentRequest()); 51 | // var paymentIntent = 52 | // await StripeService.createPaymentIntent(amount, currency); 53 | // var response = await StripePayment.confirmPaymentIntent(PaymentIntent( 54 | // clientSecret: paymentIntent['client_secret'], 55 | // paymentMethodId: paymentMethod.id)); 56 | // if (response.status == 'succeeded') { 57 | // return StripeTransactionResponse( 58 | // message: 'Transaction successful', success: true); 59 | // } else { 60 | // return StripeTransactionResponse( 61 | // message: 'Transaction failed', success: false); 62 | // } 63 | // } on PlatformException catch (error) { 64 | // return StripeService.getPlatformExceptionErrorResult(error); 65 | // } catch (error) { 66 | // return StripeTransactionResponse( 67 | // message: 'Transaction failed : $error', success: false); 68 | // } 69 | // } 70 | 71 | // static getPlatformExceptionErrorResult(err) { 72 | // String message = 'Something went wrong'; 73 | // if (err.code == 'cancelled') { 74 | // message = 'Transaction cancelled'; 75 | // } 76 | 77 | // return new StripeTransactionResponse(message: message, success: false); 78 | // } 79 | // } 80 | -------------------------------------------------------------------------------- /lib/Utils/commonWidgets.dart: -------------------------------------------------------------------------------- 1 | import 'package:bull_signal/Screens/credentials/loginRelated/login_page.dart'; 2 | import 'package:bull_signal/Screens/credentials/signUpRelated/signup_page.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | buildSignUpLoginButton({ 6 | required BuildContext context, 7 | required String btnText, 8 | required String assetImage, 9 | bool hasIcon = false, 10 | double fontSize = 20, 11 | // Color color = Colors.white, 12 | double leftRightPadding = 20.0, 13 | // textColor = Colors.black 14 | }) { 15 | return Padding( 16 | padding: const EdgeInsets.all(8), 17 | child: Card( 18 | // opacity: 0.6, 19 | color: Colors.black, 20 | margin: EdgeInsets.only( 21 | left: MediaQuery.of(context).size.width * 0.2, 22 | right: MediaQuery.of(context).size.width * 0.2), 23 | // intensity: 0.35, 24 | // style: NeuomorphicStyle.Concave, 25 | // borderRadius: BorderRadius.circular(20), 26 | child: hasIcon 27 | ? Row( 28 | children: [ 29 | Padding( 30 | padding: const EdgeInsets.only( 31 | left: 20, right: 20, top: 8, bottom: 8), 32 | child: Image.asset( 33 | assetImage, 34 | height: 25, 35 | ), 36 | ), 37 | Padding( 38 | padding: const EdgeInsets.all(8.0), 39 | child: Text( 40 | btnText, 41 | style: TextStyle( 42 | // color: textColor, 43 | fontSize: fontSize, 44 | fontWeight: FontWeight.bold), 45 | ), 46 | ) 47 | ], 48 | ) 49 | : Center( 50 | child: Padding( 51 | padding: const EdgeInsets.all(8.0), 52 | child: Text( 53 | btnText, 54 | style: TextStyle( 55 | // color: textColor, 56 | fontSize: 20, 57 | fontWeight: FontWeight.bold), 58 | ), 59 | ), 60 | ), 61 | ), 62 | ); 63 | } 64 | 65 | buildSignUpLoginText( 66 | {required BuildContext context, 67 | required String text1, 68 | required String text2, 69 | required bool moveToLogIn}) { 70 | return Padding( 71 | padding: const EdgeInsets.all(8.0), 72 | child: Row( 73 | mainAxisAlignment: MainAxisAlignment.center, 74 | children: [ 75 | Text( 76 | text1, 77 | style: const TextStyle( 78 | fontSize: 15.0, 79 | ), 80 | ), 81 | GestureDetector( 82 | onTap: () => Navigator.push( 83 | context, 84 | MaterialPageRoute( 85 | builder: (context) => 86 | moveToLogIn ? LoginPage() : const SignUpPage())), 87 | child: Text( 88 | text2, 89 | style: const TextStyle( 90 | fontWeight: FontWeight.bold, 91 | fontSize: 18.0, 92 | fontStyle: FontStyle.italic), 93 | ), 94 | ), 95 | ], 96 | )); 97 | } 98 | -------------------------------------------------------------------------------- /assets/images/signUp.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 13 | 19 | 21 | 23 | 25 | 27 | 30 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /lib/Services/authentication_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:bull_signal/Database/database.dart'; 2 | import 'package:bull_signal/Services/firebase_api.dart'; 3 | import 'package:bull_signal/Services/global_method.dart'; 4 | import 'package:bull_signal/Utils/consts.dart'; 5 | import 'package:bull_signal/announcements/announcements.dart'; 6 | import 'package:bull_signal/tools/custom_toast.dart'; 7 | import 'package:cloud_firestore/cloud_firestore.dart'; 8 | import 'package:firebase_auth/firebase_auth.dart'; 9 | import 'package:get/get.dart'; 10 | 11 | class AuthenticationService { 12 | final FirebaseAuth _firebaseAuth = FirebaseAuth.instance; 13 | Future getCurrentUser() async { 14 | return _firebaseAuth.currentUser; 15 | } 16 | 17 | Future signOut() async { 18 | await _firebaseAuth.signOut(); 19 | // UserLocalData().logOut(); 20 | } 21 | 22 | Future logIn({ 23 | required String email, 24 | required final String password, 25 | }) async { 26 | print("here"); 27 | try { 28 | // final UserCredential result = 29 | await _firebaseAuth 30 | .signInWithEmailAndPassword(email: email, password: password) 31 | .then((value) { 32 | print(" auth service login: $value"); 33 | print(" auth service login uid: ${value.user!.uid}"); 34 | 35 | // return value.user!.uid; 36 | DatabaseMethods() 37 | .fetchUserInfoFromFirebase(uid: value.user!.uid) 38 | .then((value) => Get.off(() => Announcements())); 39 | }); 40 | // return result.user!.uid; 41 | } on FirebaseAuthException catch (e) { 42 | if (e.code == 'user-not-found') { 43 | print('No user found for that email.'); 44 | GlobalMethods().printError(info: 'No user found for that email.'); 45 | } else if (e.code == 'wrong-password') { 46 | print('Wrong password provided for that user.'); 47 | } 48 | } 49 | } 50 | 51 | Future deleteUser({String? email, String? password}) async { 52 | final FirebaseAuth _auth = FirebaseAuth.instance; 53 | 54 | try { 55 | User user = _firebaseAuth.currentUser!; 56 | AuthCredential credentials = 57 | EmailAuthProvider.credential(email: email!, password: password!); 58 | print(user); 59 | UserCredential result = 60 | await user.reauthenticateWithCredential(credentials); 61 | userRef.doc(user.uid).delete(); 62 | 63 | await result.user!.delete(); 64 | return true; 65 | } catch (e) { 66 | print(e.toString()); 67 | return null; 68 | } 69 | } 70 | 71 | Future signUp({ 72 | required final String password, 73 | required final String? name, 74 | required final String? joinedAt, 75 | required final String? imageUrl, 76 | required final Timestamp? createdAt, 77 | required final String email, 78 | required final String phoneNo, 79 | final bool? isAdmin, 80 | }) async { 81 | print("1st stop"); 82 | 83 | try { 84 | final UserCredential result = await _firebaseAuth 85 | .createUserWithEmailAndPassword(email: email, password: password) 86 | .catchError((Object obj) { 87 | errorToast(message: obj.toString()); 88 | }); 89 | final UserCredential user = result; 90 | assert(user != null); 91 | assert(await user.user!.getIdToken() != null); 92 | if (user != null) { 93 | await DatabaseMethods().addUserInfoToFirebase( 94 | password: password, 95 | name: name, 96 | createdAt: createdAt, 97 | email: email, 98 | joinedAt: joinedAt, 99 | userId: user.user!.uid, 100 | phoneNo: phoneNo, 101 | imageUrl: imageUrl, 102 | isAdmin: false); 103 | } 104 | return user; 105 | } on FirebaseAuthException catch (e) { 106 | GlobalMethods().printError(info: e.message!); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: bull_signal 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `flutter 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.15.0 <3.0.0" 22 | 23 | # Dependencies specify other packages that your package needs in order to work. 24 | # To automatically upgrade your package dependencies to the latest versions 25 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 26 | # dependencies can be manually updated by changing the version numbers below to 27 | # the latest version available on pub.dev. To see which dependencies have newer 28 | # versions available, run `flutter pub outdated`. 29 | dependencies: 30 | flutter: 31 | sdk: flutter 32 | firebase_storage: 33 | firebase_auth: 34 | firebase_messaging: 35 | cloud_firestore: 36 | fluttertoast: 37 | get_storage: 38 | lottie: 39 | cached_network_image: 40 | path_provider: 41 | firebase_core: 42 | flutter_local_notifications: 43 | webview_flutter: 44 | image: 45 | image_picker: 46 | timeago: 47 | flutter_webview_plugin: 48 | flutter_svg: 49 | 50 | # The following adds the Cupertino Icons font to your application. 51 | # Use with the CupertinoIcons class for iOS style icons. 52 | cupertino_icons: ^1.0.2 53 | 54 | dev_dependencies: 55 | flutter_test: 56 | sdk: flutter 57 | 58 | # The "flutter_lints" package below contains a set of recommended lints to 59 | # encourage good coding practices. The lint set provided by the package is 60 | # activated in the `analysis_options.yaml` file located at the root of your 61 | # package. See that file for information about deactivating specific lint 62 | # rules and activating additional ones. 63 | flutter_lints: ^1.0.0 64 | 65 | # For information on the generic Dart part of this file, see the 66 | # following page: https://dart.dev/tools/pub/pubspec 67 | 68 | # The following section is specific to Flutter. 69 | flutter: 70 | 71 | # The following line ensures that the Material Icons font is 72 | # included with your application, so that you can use the icons in 73 | # the material Icons class. 74 | uses-material-design: true 75 | 76 | # To add assets to your application, add an assets section, like this: 77 | assets: 78 | - assets/images/ 79 | 80 | # An image asset can refer to one or more resolution-specific "variants", see 81 | # https://flutter.dev/assets-and-images/#resolution-aware. 82 | 83 | # For details regarding adding assets from package dependencies, see 84 | # https://flutter.dev/assets-and-images/#from-packages 85 | 86 | # To add custom fonts to your application, add a fonts section here, 87 | # in this "flutter" section. Each entry in this list should have a 88 | # "family" key with the font family name, and a "fonts" key with a 89 | # list giving the asset and other descriptors for the font. For 90 | # example: 91 | # fonts: 92 | # - family: Schyler 93 | # fonts: 94 | # - asset: fonts/Schyler-Regular.ttf 95 | # - asset: fonts/Schyler-Italic.ttf 96 | # style: italic 97 | # - family: Trajan Pro 98 | # fonts: 99 | # - asset: fonts/TrajanPro.ttf 100 | # - asset: fonts/TrajanPro_Bold.ttf 101 | # weight: 700 102 | # 103 | # For details regarding fonts from package dependencies, 104 | # see https://flutter.dev/custom-fonts/#from-packages 105 | -------------------------------------------------------------------------------- /lib/Screens/credentials/loginRelated/forget_password_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:bull_signal/Utils/commonWidgets.dart'; 2 | import 'package:bull_signal/tools/loading.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class ForgetPasswordPage extends StatefulWidget { 6 | const ForgetPasswordPage({Key? key}) : super(key: key); 7 | 8 | @override 9 | _ForgetPasswordPageState createState() => _ForgetPasswordPageState(); 10 | } 11 | 12 | class _ForgetPasswordPageState extends State { 13 | final TextEditingController _emailController = TextEditingController(); 14 | final _textFormKey = GlobalKey(); 15 | 16 | bool _isLoading = false; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return SafeArea( 21 | child: Scaffold( 22 | body: SingleChildScrollView( 23 | child: Stack( 24 | children: [ 25 | Column( 26 | children: [ 27 | Padding( 28 | padding: const EdgeInsets.all(20.0), 29 | child: Hero( 30 | tag: "logo", 31 | child: Image.asset( 32 | 'logo', 33 | height: 90, 34 | )), 35 | ), 36 | Center( 37 | child: Padding( 38 | padding: const EdgeInsets.all(8.0), 39 | child: Image.asset( 40 | 'forgetPassPageIcon', 41 | height: 60, 42 | ), 43 | ), 44 | ), 45 | const SizedBox( 46 | height: 20, 47 | ), 48 | const Padding( 49 | padding: EdgeInsets.all(8.0), 50 | child: Hero( 51 | tag: "passFor", 52 | child: Text( 53 | "Forgot Password?", 54 | style: TextStyle( 55 | fontWeight: FontWeight.bold, 56 | fontSize: 20, 57 | ), 58 | ), 59 | ), 60 | ), 61 | Form( 62 | key: _textFormKey, 63 | child: Padding( 64 | padding: const EdgeInsets.all(12.0), 65 | child: TextFormField( 66 | controller: _emailController, 67 | keyboardType: TextInputType.text, 68 | validator: (String? val) { 69 | if (val == null) { 70 | return null; 71 | } 72 | if (val.isEmpty) { 73 | return "Field is Empty"; 74 | } else if (!val.contains("@") || 75 | val.trim().length < 4) { 76 | return "Invalid E-mail!"; 77 | } else { 78 | return null; 79 | } 80 | }, 81 | // onSaved: (val) => phoneNo = val, 82 | autofocus: true, 83 | decoration: const InputDecoration( 84 | border: InputBorder.none, 85 | filled: true, 86 | labelText: "E-mail", 87 | labelStyle: TextStyle(fontSize: 15.0), 88 | hintText: "Please enter your valid E-mail", 89 | ), 90 | ), 91 | ), 92 | ), 93 | const SizedBox( 94 | height: 10, 95 | ), 96 | GestureDetector( 97 | onTap: () => handleForgetPass(), 98 | child: buildSignUpLoginButton( 99 | context: context, 100 | btnText: "Continue", 101 | hasIcon: false, 102 | // textColor: Colors.white, 103 | // color: const Color(0xff387A53), 104 | assetImage: ''), 105 | ), 106 | ], 107 | ), 108 | _isLoading ? const LoadingIndicator() : Container(), 109 | ], 110 | ), 111 | ), 112 | bottomSheet: buildSignUpLoginText( 113 | context: context, 114 | text1: "Don't have an account ", 115 | text2: "Sign Up", 116 | moveToLogIn: false), 117 | ), 118 | ); 119 | } 120 | 121 | getPass({ 122 | required String email, 123 | }) async {} 124 | 125 | handleForgetPass() async { 126 | final FormState? _form = _textFormKey.currentState; 127 | 128 | if (_form == null) { 129 | return null; 130 | } 131 | if (_form.validate()) { 132 | setState(() { 133 | _isLoading = false; 134 | }); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /AppIcons/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | {"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"72x72","expected-size":"72","filename":"72.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"76x76","expected-size":"152","filename":"152.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"50x50","expected-size":"100","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"76x76","expected-size":"76","filename":"76.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"50x50","expected-size":"50","filename":"50.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"72x72","expected-size":"144","filename":"144.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"40x40","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"20x20","expected-size":"20","filename":"20.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"idiom":"watch","filename":"172.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"38mm","scale":"2x","size":"86x86","expected-size":"172","role":"quickLook"},{"idiom":"watch","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"38mm","scale":"2x","size":"40x40","expected-size":"80","role":"appLauncher"},{"idiom":"watch","filename":"88.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"40mm","scale":"2x","size":"44x44","expected-size":"88","role":"appLauncher"},{"idiom":"watch","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"44mm","scale":"2x","size":"50x50","expected-size":"100","role":"appLauncher"},{"idiom":"watch","filename":"196.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"42mm","scale":"2x","size":"98x98","expected-size":"196","role":"quickLook"},{"idiom":"watch","filename":"216.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"44mm","scale":"2x","size":"108x108","expected-size":"216","role":"quickLook"},{"idiom":"watch","filename":"48.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"38mm","scale":"2x","size":"24x24","expected-size":"48","role":"notificationCenter"},{"idiom":"watch","filename":"55.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"42mm","scale":"2x","size":"27.5x27.5","expected-size":"55","role":"notificationCenter"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"watch","role":"companionSettings","scale":"3x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"watch","role":"companionSettings","scale":"2x"},{"size":"1024x1024","expected-size":"1024","filename":"1024.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"watch-marketing","scale":"1x"},{"size":"128x128","expected-size":"128","filename":"128.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"256x256","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"128x128","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"256x256","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"512x512","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"16","filename":"16.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"64","filename":"64.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"512x512","expected-size":"1024","filename":"1024.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"}]} -------------------------------------------------------------------------------- /lib/announcements/announcements.dart: -------------------------------------------------------------------------------- 1 | import 'package:bull_signal/Models/announcements_model.dart'; 2 | import 'package:bull_signal/Screens/comments_n_chat.dart'; 3 | import 'package:bull_signal/Screens/user_info.dart'; 4 | import 'package:bull_signal/Services/firebase_api.dart'; 5 | import 'package:bull_signal/Utils/consts.dart'; 6 | import 'package:bull_signal/tools/loading.dart'; 7 | import 'package:cached_network_image/cached_network_image.dart'; 8 | import 'package:firebase_auth/firebase_auth.dart'; 9 | import 'package:flutter/material.dart'; 10 | import 'package:get/get.dart'; 11 | import 'addAnnouncements.dart'; 12 | 13 | class Announcements extends StatefulWidget { 14 | @override 15 | _AnnouncementsState createState() => _AnnouncementsState(); 16 | } 17 | 18 | class _AnnouncementsState extends State { 19 | List allAnnouncements = []; 20 | bool _isLoading = false; 21 | @override 22 | void initState() { 23 | super.initState(); 24 | getAnnouncements(); 25 | } 26 | 27 | getAnnouncements() async { 28 | setState(() { 29 | _isLoading = true; 30 | this.allAnnouncements = []; 31 | }); 32 | List allAnnouncements = 33 | await FirebaseApi().getAnnouncements(); 34 | setState(() { 35 | this.allAnnouncements = allAnnouncements; 36 | _isLoading = false; 37 | }); 38 | } 39 | 40 | @override 41 | Widget build(BuildContext context) { 42 | return Scaffold( 43 | floatingActionButton: currentUser == null 44 | ? const LoadingIndicator() 45 | : currentUser!.isAdmin! 46 | ? FloatingActionButton( 47 | onPressed: () => Navigator.of(context) 48 | .push(MaterialPageRoute( 49 | builder: (context) => AddAnnouncements(), 50 | )) 51 | .then((value) => getAnnouncements()), 52 | child: const Icon(Icons.add), 53 | tooltip: "Add New Announcement", 54 | ) 55 | : Container(), 56 | appBar: AppBar( 57 | elevation: 0, 58 | centerTitle: true, 59 | title: Text( 60 | "Announcements", 61 | style: titleTextStyle( 62 | color: Theme.of(context).primaryTextTheme.bodyText1!.color!), 63 | ), 64 | actions: [ 65 | IconButton( 66 | onPressed: () => Navigator.of(context).push(MaterialPageRoute( 67 | builder: (context) => UserInfoScreen(), 68 | )), 69 | icon: Icon(Icons.person)) 70 | ], 71 | ), 72 | body: RefreshIndicator( 73 | onRefresh:()=> getAnnouncements(), 74 | child: ListView( 75 | shrinkWrap: true, 76 | physics: const BouncingScrollPhysics(), 77 | children: [ 78 | ListView.builder( 79 | shrinkWrap: true, 80 | physics: const NeverScrollableScrollPhysics(), 81 | itemBuilder: (context, index) { 82 | return Padding( 83 | padding: const EdgeInsets.all(12.0), 84 | child: GestureDetector( 85 | onLongPress: () { 86 | return currentUser!.isAdmin! 87 | ? deleteNotification( 88 | context, allAnnouncements[index].announcementId!) 89 | : null; 90 | }, 91 | child: _isLoading 92 | ? const LoadingIndicator() 93 | : Card( 94 | shape: RoundedRectangleBorder( 95 | borderRadius: BorderRadius.circular(12)), 96 | child: Column( 97 | crossAxisAlignment: 98 | // allAnnouncements[index].imageUrl != null 99 | // ? CrossAxisAlignment.center 100 | // : 101 | CrossAxisAlignment.start, 102 | children: [ 103 | allAnnouncements[index].imageUrl != null 104 | ? ClipRRect( 105 | borderRadius: BorderRadius.circular(12), 106 | child: CachedNetworkImage( 107 | imageUrl: allAnnouncements[index] 108 | .imageUrl!), 109 | ) 110 | : Container(), 111 | Padding( 112 | padding: const EdgeInsets.all(8.0), 113 | child: Text( 114 | allAnnouncements[index].announcementTitle!, 115 | style: customTextStyle(), 116 | ), 117 | ), 118 | Padding( 119 | padding: const EdgeInsets.all(8.0), 120 | child: Text( 121 | allAnnouncements[index].description!, 122 | // style: customTextStyle(fontSize: 18), 123 | ), 124 | ), 125 | Padding( 126 | padding: const EdgeInsets.all(8.0), 127 | child: GestureDetector( 128 | onTap: () => Navigator.of(context) 129 | .push(MaterialPageRoute( 130 | builder: (context) => CommentsNChat( 131 | postId: allAnnouncements[index] 132 | .announcementId, 133 | isPostComment: true, 134 | chatId: allAnnouncements[index] 135 | .announcementId, 136 | isAdmin: currentUser!.isAdmin, 137 | isProductComment: false, 138 | ), 139 | )), 140 | child: const Text( 141 | 'View All Comments', 142 | style: TextStyle( 143 | color: Colors.cyan, 144 | fontWeight: FontWeight.bold), 145 | )), 146 | ), 147 | ], 148 | ), 149 | ), 150 | ), 151 | ); 152 | }, 153 | itemCount: allAnnouncements.length, 154 | ), 155 | ], 156 | ), 157 | ), 158 | ); 159 | } 160 | 161 | deleteNotification(BuildContext parentContext, String id) { 162 | return showDialog( 163 | context: parentContext, 164 | builder: (context) { 165 | return SimpleDialog( 166 | children: [ 167 | SimpleDialogOption( 168 | onPressed: () { 169 | getAnnouncements(); 170 | Navigator.pop(context); 171 | }, 172 | child: const Text( 173 | 'Delete Announcement', 174 | ), 175 | ), 176 | SimpleDialogOption( 177 | onPressed: () => Navigator.pop(context), 178 | child: const Text('Cancel'), 179 | ) 180 | ], 181 | ); 182 | }); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /lib/Screens/credentials/loginRelated/login_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:bull_signal/Database/database.dart'; 2 | import 'package:bull_signal/Services/authentication_service.dart'; 3 | import 'package:bull_signal/Utils/commonWidgets.dart'; 4 | import 'package:bull_signal/Utils/consts.dart'; 5 | import 'package:bull_signal/Utils/palette.dart'; 6 | import 'package:bull_signal/announcements/announcements.dart'; 7 | import 'package:bull_signal/tools/custom_toast.dart'; 8 | import 'package:bull_signal/tools/loading.dart'; 9 | import 'package:flutter/material.dart'; 10 | import 'package:get/get.dart'; 11 | import 'forget_password_page.dart'; 12 | 13 | class LoginPage extends StatefulWidget { 14 | LoginPage({Key? key, this.currentUserString}) : super(key: key); 15 | String? currentUserString; 16 | @override 17 | _LoginPageState createState() => _LoginPageState(); 18 | } 19 | 20 | class _LoginPageState extends State { 21 | bool _obscureText = true; 22 | final TextEditingController _passwordController = TextEditingController(); 23 | final TextEditingController _emailController = TextEditingController(); 24 | final _textFormKey = GlobalKey(); 25 | 26 | bool _isLoading = false; 27 | @override 28 | Widget build(BuildContext context) { 29 | print(widget.currentUserString); 30 | return SafeArea( 31 | child: Scaffold( 32 | body: Stack( 33 | children: [ 34 | SingleChildScrollView( 35 | child: Padding( 36 | padding: const EdgeInsets.all(12.0), 37 | child: Form( 38 | key: _textFormKey, 39 | child: Column( 40 | children: [ 41 | const SizedBox( 42 | height: 10, 43 | ), 44 | Padding( 45 | padding: const EdgeInsets.all(20.0), 46 | child: Hero( 47 | tag: "logo", 48 | child: Image.asset( 49 | logo, 50 | height: 90, 51 | )), 52 | ), 53 | const SizedBox( 54 | height: 10, 55 | ), 56 | Padding( 57 | padding: const EdgeInsets.only(left: 12.0), 58 | child: TextFormField( 59 | controller: _emailController, 60 | keyboardType: TextInputType.text, 61 | validator: (val) { 62 | if (val == null) { 63 | return null; 64 | } 65 | if (val.isEmpty) { 66 | return "Field is Empty"; 67 | } else if (!val.contains("@") || 68 | val.trim().length < 4) { 69 | return "Invalid E-mail!"; 70 | } else { 71 | return null; 72 | } 73 | }, 74 | // onSaved: (val) => phoneNo = val, 75 | autofocus: true, 76 | decoration: const InputDecoration( 77 | // border: InputBorder.none, 78 | labelText: "E-mail", 79 | labelStyle: TextStyle(fontSize: 15.0), 80 | hintText: "Please enter your valid E-mail", 81 | ), 82 | ), 83 | ), 84 | const SizedBox( 85 | height: 10, 86 | ), 87 | Padding( 88 | padding: const EdgeInsets.only( 89 | left: 12.0, 90 | ), 91 | child: TextFormField( 92 | obscureText: _obscureText, 93 | validator: (val) { 94 | if (val == null) { 95 | return null; 96 | } 97 | if (val.length < 6) { 98 | return 'Password Too Short'; 99 | } else { 100 | return null; 101 | } 102 | }, 103 | controller: _passwordController, 104 | decoration: InputDecoration( 105 | suffixIcon: GestureDetector( 106 | onTap: () { 107 | setState(() { 108 | _obscureText = !_obscureText; 109 | }); 110 | }, 111 | child: Icon(_obscureText 112 | ? Icons.visibility 113 | : Icons.visibility_off), 114 | ), 115 | // border: InputBorder.none, 116 | // filled: true, 117 | // fillColor: Colors.white, 118 | labelText: "Password", 119 | hintText: "Enter a valid password, min length 6", 120 | ), 121 | ), 122 | ), 123 | const SizedBox( 124 | height: 10, 125 | ), 126 | Padding( 127 | padding: const EdgeInsets.only( 128 | left: 200, top: 8, bottom: 8, right: 12), 129 | child: GestureDetector( 130 | onTap: () => Navigator.push( 131 | context, 132 | MaterialPageRoute( 133 | builder: (context) => 134 | const ForgetPasswordPage())), 135 | child: const Card( 136 | color: Colors.black26, 137 | child: Padding( 138 | padding: EdgeInsets.all(8.0), 139 | child: Hero( 140 | tag: "passFor", 141 | child: Text( 142 | "Forgot Password?", 143 | style: TextStyle( 144 | fontWeight: FontWeight.bold, 145 | fontSize: 15, 146 | // color: Colors.black 147 | ), 148 | ), 149 | ), 150 | ), 151 | ), 152 | ), 153 | ), 154 | Padding( 155 | padding: const EdgeInsets.all(8.0), 156 | child: GestureDetector( 157 | onTap: () => _handleLogin(), 158 | child: buildSignUpLoginButton( 159 | context: context, 160 | btnText: "Log In", 161 | assetImage: logo, 162 | // color: containerColor, 163 | hasIcon: false, 164 | ), 165 | ), 166 | ), 167 | 168 | const SizedBox( 169 | height: 20, 170 | ), 171 | // Move to Sign Up Page 172 | ], 173 | ), 174 | ), 175 | ), 176 | ), 177 | _isLoading ? LoadingIndicator() : Container(), 178 | ], 179 | ), 180 | bottomSheet: buildSignUpLoginText( 181 | context: context, 182 | text1: "Don't have an account ", 183 | text2: "Sign Up", 184 | moveToLogIn: false), 185 | ), 186 | ); 187 | } 188 | 189 | void _handleLogin() async { 190 | final _form = _textFormKey.currentState; 191 | if (_form == null) { 192 | return null; 193 | } 194 | if (_form.validate()) { 195 | setState(() { 196 | _isLoading = true; 197 | }); 198 | 199 | final String? email = _emailController.text; 200 | final String? password = _passwordController.text; 201 | String? userId = await AuthenticationService() 202 | .logIn(email: email!, password: password!) 203 | .onError((error, stackTrace) { 204 | errorToast(message: "Please Try again"); 205 | setState(() { 206 | _isLoading = false; 207 | _emailController.clear(); 208 | _passwordController.clear(); 209 | }); 210 | return null; 211 | }); 212 | print(userId); 213 | await DatabaseMethods() 214 | .fetchUserInfoFromFirebase(uid: userId!) 215 | .then((value) => setState(() { 216 | _isLoading = false; 217 | Get.off(() => Announcements()); 218 | })); 219 | } 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /lib/Screens/credentials/signUpRelated/signup_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:bull_signal/Services/authentication_service.dart'; 2 | import 'package:bull_signal/Utils/commonWidgets.dart'; 3 | import 'package:bull_signal/Utils/consts.dart'; 4 | import 'package:bull_signal/Utils/palette.dart'; 5 | import 'package:bull_signal/announcements/announcements.dart'; 6 | import 'package:bull_signal/tools/custom_toast.dart'; 7 | import 'package:bull_signal/tools/loading.dart'; 8 | import 'package:firebase_auth/firebase_auth.dart'; 9 | import 'package:flutter/material.dart'; 10 | 11 | class SignUpPage extends StatefulWidget { 12 | const SignUpPage({Key? key}) : super(key: key); 13 | 14 | @override 15 | _SignUpPageState createState() => _SignUpPageState(); 16 | } 17 | 18 | class _SignUpPageState extends State { 19 | bool _obscureText = true; 20 | final TextEditingController _passwordController = TextEditingController(); 21 | final TextEditingController _confirmPasswordController = 22 | TextEditingController(); 23 | 24 | final TextEditingController _emailController = TextEditingController(); 25 | final TextEditingController _userNameController = TextEditingController(); 26 | final TextEditingController _phoneNoController = TextEditingController(); 27 | // TextEditingController _addressController = TextEditingController(); 28 | final _textFormKey = GlobalKey(); 29 | 30 | bool _isLoading = false; 31 | @override 32 | Widget build(BuildContext context) { 33 | return SafeArea( 34 | child: Scaffold( 35 | body: Stack( 36 | children: [ 37 | SingleChildScrollView( 38 | child: Padding( 39 | padding: const EdgeInsets.all(12.0), 40 | child: Form( 41 | key: _textFormKey, 42 | child: Column( 43 | children: [ 44 | const SizedBox( 45 | height: 10, 46 | ), 47 | Padding( 48 | padding: const EdgeInsets.all(20.0), 49 | child: Hero( 50 | tag: "logo", 51 | child: Image.asset( 52 | logo, 53 | height: 90, 54 | )), 55 | ), 56 | const SizedBox( 57 | height: 10, 58 | ), 59 | edittedTextField( 60 | hintText: "Enter a valid user name, min length 6", 61 | controller: _userNameController, 62 | isPass: false, 63 | lablelText: "Username", 64 | ), 65 | const SizedBox( 66 | height: 10, 67 | ), 68 | edittedTextField( 69 | hintText: "Enter a valid email address", 70 | controller: _emailController, 71 | isPass: false, 72 | isEmail: true, 73 | lablelText: "Email Address", 74 | ), 75 | const SizedBox( 76 | height: 10, 77 | ), 78 | edittedTextField( 79 | hintText: "Enter a valid password, min length 6", 80 | valText: 'Password Too Short', 81 | controller: _passwordController, 82 | isPass: true, 83 | lablelText: "Password", 84 | obscureText: _obscureText, 85 | ), 86 | const SizedBox( 87 | height: 10, 88 | ), 89 | edittedTextField( 90 | hintText: "Enter same password as above", 91 | valText: 'Password Too Short', 92 | controller: _confirmPasswordController, 93 | isPass: true, 94 | lablelText: "Confirm Password", 95 | obscureText: _obscureText, 96 | ), 97 | const SizedBox( 98 | height: 10, 99 | ), 100 | edittedTextField( 101 | hintText: "Enter a valid phone number", 102 | controller: _phoneNoController, 103 | isPass: false, 104 | valText: 'Phone number Too Short', 105 | lablelText: "Phone Number", 106 | ), 107 | const SizedBox( 108 | height: 10, 109 | ), 110 | 111 | Padding( 112 | padding: const EdgeInsets.all(8.0), 113 | child: GestureDetector( 114 | onTap: () => _handleSignUp(context), 115 | child: buildSignUpLoginButton( 116 | context: context, 117 | btnText: "Sign Up", 118 | assetImage: logo, 119 | // color: containerColor, 120 | hasIcon: false), 121 | ), 122 | ), 123 | 124 | const SizedBox( 125 | height: 20, 126 | ), 127 | // Move to Sign Up Page 128 | ], 129 | ), 130 | ), 131 | ), 132 | ), 133 | _isLoading ? const LoadingIndicator() : Container(), 134 | ], 135 | ), 136 | bottomSheet: buildSignUpLoginText( 137 | context: context, 138 | text1: "Already Have an account ", 139 | text2: "Sign In", 140 | moveToLogIn: true), 141 | ), 142 | ); 143 | } 144 | 145 | emailValidation(val) { 146 | if (val == null) { 147 | return null; 148 | } 149 | if (val.isEmpty) { 150 | return "Field is Empty"; 151 | } else if (!val.contains("@") || val.trim().length < 4) { 152 | return "Invalid E-mail!"; 153 | } else { 154 | return null; 155 | } 156 | } 157 | 158 | Container edittedTextField({ 159 | String? lablelText, 160 | String? hintText, 161 | bool? isEmail = false, 162 | bool? obscureText = true, 163 | String? valText, 164 | int valLength = 6, 165 | TextEditingController? controller, 166 | bool? isPass, 167 | }) { 168 | return Container( 169 | child: Padding( 170 | padding: const EdgeInsets.only( 171 | left: 12.0, 172 | ), 173 | child: TextFormField( 174 | obscureText: isPass! ? true : false, 175 | validator: (val) { 176 | if (!isEmail!) { 177 | if (val == null) { 178 | return null; 179 | } 180 | if (val.length < valLength) { 181 | return valText; 182 | } else { 183 | return null; 184 | } 185 | } else { 186 | return emailValidation(val); 187 | } 188 | }, 189 | controller: controller, 190 | decoration: InputDecoration( 191 | suffixIcon: isPass 192 | ? GestureDetector( 193 | onTap: () { 194 | setState(() { 195 | _obscureText = !_obscureText; 196 | }); 197 | }, 198 | child: Icon( 199 | _obscureText ? Icons.visibility : Icons.visibility_off), 200 | ) 201 | : null, 202 | // filled: true, 203 | // fillColor: Colors.white, 204 | labelText: lablelText, 205 | hintText: hintText, 206 | ), 207 | ), 208 | ), 209 | ); 210 | } 211 | 212 | void _handleSignUp(BuildContext context) async { 213 | final _form = _textFormKey.currentState; 214 | if (_form == null) { 215 | return null; 216 | } 217 | if (_form.validate()) { 218 | setState(() { 219 | _isLoading = true; 220 | }); 221 | // UserModel userModel = UserModel(); 222 | 223 | UserCredential? _user = await AuthenticationService() 224 | .signUp( 225 | email: _emailController.text, 226 | isAdmin: false, 227 | password: _passwordController.text, 228 | name: _userNameController.text, 229 | createdAt: null, 230 | joinedAt: DateTime.now().toString(), 231 | imageUrl: '', 232 | phoneNo: '', 233 | ) 234 | .onError((error, stackTrace) { 235 | setState(() { 236 | _isLoading = false; 237 | }); 238 | errorToast(message: "$error"); 239 | return null; 240 | }); 241 | setState(() { 242 | _isLoading = false; 243 | }); 244 | Navigator.of(context).pop(); 245 | if (_user != null) { 246 | successToast(message: 'Successfully Registered'); 247 | Navigator.of(context).pushReplacement( 248 | MaterialPageRoute(builder: ((context) => Announcements()))); 249 | } 250 | } 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /lib/Screens/Admin/allUsers.dart: -------------------------------------------------------------------------------- 1 | import 'package:bull_signal/Models/users.dart'; 2 | import 'package:bull_signal/Screens/comments_n_chat.dart'; 3 | import 'package:bull_signal/Screens/credentials/loginRelated/login_page.dart'; 4 | import 'package:bull_signal/Services/authentication_service.dart'; 5 | import 'package:bull_signal/Utils/consts.dart'; 6 | import 'package:bull_signal/tools/custom_toast.dart'; 7 | import 'package:bull_signal/tools/loading.dart'; 8 | import 'package:cloud_firestore/cloud_firestore.dart'; 9 | import 'package:flutter/material.dart'; 10 | 11 | import 'commentsNChatAdmin.dart'; 12 | 13 | class UserNSearch extends StatefulWidget { 14 | const UserNSearch({Key? key}) : super(key: key); 15 | 16 | // final UserModel currentUser; 17 | // UserNSearch({this.currentUser}); 18 | @override 19 | _UserNSearchState createState() => _UserNSearchState(); 20 | } 21 | 22 | class _UserNSearchState extends State 23 | with AutomaticKeepAliveClientMixin { 24 | Future? searchResultsFuture; 25 | TextEditingController searchController = TextEditingController(); 26 | 27 | String typeSelected = 'users'; 28 | handleSearch(String query) { 29 | if (currentUser!.isAdmin!) { 30 | Future users = 31 | userRef.where("name", isGreaterThanOrEqualTo: query).get(); 32 | setState(() { 33 | searchResultsFuture = users; 34 | }); 35 | } else { 36 | Future users = userRef 37 | .where("name", isGreaterThanOrEqualTo: query) 38 | .where("isAdmin", isNotEqualTo: true) 39 | .get(); 40 | setState(() { 41 | searchResultsFuture = users; 42 | }); 43 | } 44 | } 45 | 46 | clearSearch() { 47 | searchController.clear(); 48 | } 49 | 50 | AppBar buildSearchField(context) { 51 | return AppBar( 52 | // backgroundColor: Theme.of(context).accentColor, 53 | title: TextFormField( 54 | controller: searchController, 55 | decoration: InputDecoration( 56 | hintText: "Search", 57 | // hintStyle: TextStyle(color: Colors.black), 58 | prefixIcon: const Icon( 59 | Icons.search, 60 | // color: ColorsConsts.subTitle, 61 | ), 62 | suffixIcon: IconButton( 63 | icon: const Icon( 64 | Icons.clear, 65 | // color: ColorsConsts.subTitle, 66 | ), 67 | onPressed: clearSearch, 68 | )), 69 | onFieldSubmitted: handleSearch, 70 | ), 71 | ); 72 | } 73 | 74 | buildSearchResult() { 75 | return FutureBuilder( 76 | future: searchResultsFuture, 77 | builder: (context, snapshot) { 78 | if (!snapshot.hasData) { 79 | return const LoadingIndicator(); 80 | } 81 | List searchResults = []; 82 | snapshot.data!.docs.forEach((doc) { 83 | String completeName = doc["name"].toString().toLowerCase().trim(); 84 | if (completeName.contains(searchController.text)) { 85 | AppUserModel user = AppUserModel.fromDocument(doc); 86 | setState(() { 87 | UserResult searchResult = UserResult(user); 88 | searchResults.add(searchResult); 89 | }); 90 | } 91 | }); 92 | return ListView( 93 | children: searchResults, 94 | ); 95 | }, 96 | ); 97 | } 98 | 99 | bool get wantKeepAlive => true; 100 | @override 101 | Widget build(BuildContext context) { 102 | super.build(context); 103 | return SafeArea( 104 | child: Scaffold( 105 | appBar: buildSearchField(context), 106 | body: 107 | searchResultsFuture == null ? buildAllUsers() : buildSearchResult(), 108 | ), 109 | ); 110 | } 111 | 112 | buildAllUsers() { 113 | return StreamBuilder( 114 | stream: userRef.snapshots(), 115 | builder: (context, snapshot) { 116 | if (!snapshot.hasData) { 117 | return const LoadingIndicator(); 118 | } 119 | List userResults = []; 120 | List allAdmins = []; 121 | 122 | snapshot.data!.docs.forEach((doc) { 123 | AppUserModel user = AppUserModel.fromDocument(doc); 124 | 125 | //remove auth user from recommended list 126 | if (user.isAdmin!) { 127 | UserResult adminResult = UserResult(user); 128 | allAdmins.add(adminResult); 129 | } else { 130 | UserResult userResult = UserResult(user); 131 | userResults.add(userResult); 132 | } 133 | }); 134 | return ListView( 135 | physics: const BouncingScrollPhysics(), 136 | children: [ 137 | // currentUser!.isAdmin! 138 | // ? 139 | SizedBox( 140 | height: 100, 141 | child: Padding( 142 | padding: const EdgeInsets.all(8.0), 143 | child: Row( 144 | children: [ 145 | Row( 146 | crossAxisAlignment: CrossAxisAlignment.center, 147 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 148 | children: [ 149 | Padding( 150 | padding: const EdgeInsets.all(8), 151 | child: GestureDetector( 152 | onTap: () { 153 | setState(() { 154 | typeSelected = "users"; 155 | }); 156 | }, 157 | child: Card( 158 | child: Padding( 159 | padding: const EdgeInsets.all(8.0), 160 | child: Text( 161 | "All Users ${userResults.length}", 162 | style: const TextStyle(fontSize: 20.0), 163 | ), 164 | ), 165 | ), 166 | ), 167 | ), 168 | ], 169 | ), 170 | Row( 171 | crossAxisAlignment: CrossAxisAlignment.center, 172 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 173 | children: [ 174 | Padding( 175 | padding: const EdgeInsets.all(8), 176 | child: GestureDetector( 177 | onTap: () { 178 | setState(() { 179 | typeSelected = "admin"; 180 | }); 181 | }, 182 | child: Card( 183 | child: Padding( 184 | padding: const EdgeInsets.all(8.0), 185 | child: Text( 186 | "All Admins ${allAdmins.length}", 187 | style: const TextStyle(fontSize: 20.0), 188 | ), 189 | ), 190 | ), 191 | ), 192 | ), 193 | ], 194 | ), 195 | ], 196 | ), 197 | ), 198 | ), 199 | // : Container(), 200 | typeSelected == 'admin' 201 | ? Column( 202 | children: allAdmins, 203 | ) 204 | : const Text(""), 205 | typeSelected == 'users' 206 | ? Column( 207 | children: userResults, 208 | ) 209 | : const Text(''), 210 | ], 211 | ); 212 | }); 213 | } 214 | } 215 | 216 | class UserResult extends StatelessWidget { 217 | final AppUserModel user; 218 | UserResult(this.user); 219 | @override 220 | Widget build(BuildContext context) { 221 | return Column( 222 | children: [ 223 | GestureDetector( 224 | onLongPress: () => makeAdmin(context), 225 | onTap: () { 226 | if (user.id != currentUser!.id) { 227 | Navigator.of(context).push(MaterialPageRoute( 228 | builder: (context) => CommentsNChatAdmin( 229 | chatId: user.id, 230 | chatNotificationToken: user.androidNotificationToken), 231 | )); 232 | } 233 | }, 234 | child: Padding( 235 | padding: const EdgeInsets.all(8.0), 236 | child: Card( 237 | child: ListTile( 238 | leading: const CircleAvatar( 239 | backgroundColor: Colors.grey, 240 | child: Icon(Icons.person), 241 | ), 242 | title: Text( 243 | user.name.toString(), 244 | style: const TextStyle(fontWeight: FontWeight.bold), 245 | ), 246 | subtitle: Text( 247 | user.name.toString(), 248 | ), 249 | trailing: Text(user.isAdmin != null && user.isAdmin == true 250 | ? "Admin" 251 | : "User"), 252 | ), 253 | ), 254 | ), 255 | ), 256 | ], 257 | ); 258 | } 259 | 260 | makeAdmin(BuildContext parentContext) { 261 | return showDialog( 262 | context: parentContext, 263 | builder: (context) { 264 | return SimpleDialog( 265 | children: [ 266 | user.isAdmin! && user.id != currentUser!.id 267 | ? SimpleDialogOption( 268 | onPressed: () { 269 | Navigator.pop(context); 270 | makeAdminFunc("Rank changed to User"); 271 | }, 272 | child: const Text( 273 | 'Make User', 274 | ), 275 | ) 276 | : SimpleDialogOption( 277 | onPressed: () { 278 | Navigator.pop(context); 279 | makeAdminFunc("Upgraded to Admin"); 280 | }, 281 | child: const Text( 282 | 'Make Admin', 283 | ), 284 | ), 285 | SimpleDialogOption( 286 | onPressed: () { 287 | Navigator.pop(context); 288 | deleteUser(user.email!, user.password!); 289 | }, 290 | child: const Text( 291 | 'Delete User', 292 | style: TextStyle(color: Colors.red), 293 | ), 294 | ), 295 | SimpleDialogOption( 296 | onPressed: () => Navigator.pop(context), 297 | child: const Text('Cancel'), 298 | ) 299 | ], 300 | ); 301 | }); 302 | } 303 | 304 | void makeAdminFunc(String msg) { 305 | userRef.doc(user.id).update({"isAdmin": !user.isAdmin!}); 306 | addToFeed(msg); 307 | 308 | // BotToast.showText(text: msg); 309 | } 310 | 311 | addToFeed(String msg) { 312 | // activityFeedRef.doc(user.id).collection('feedItems').add({ 313 | // "type": "mercReq", 314 | // "commentData": msg, 315 | // "userName": user.displayName, 316 | // "userId": user.id, 317 | // "userProfileImg": user.photoUrl, 318 | // "ownerId": currentUser.id, 319 | // "mediaUrl": currentUser.photoUrl, 320 | // "timestamp": timestamp, 321 | // "productId": "", 322 | // }); 323 | } 324 | void deleteUser(String email, String password) async { 325 | AuthenticationService().deleteUser(email: email, password: password); 326 | successToast(message: 'User Deleted Refresh'); 327 | } 328 | } 329 | -------------------------------------------------------------------------------- /lib/Screens/Admin/commentsNChatAdmin.dart: -------------------------------------------------------------------------------- 1 | import 'package:bull_signal/Models/users.dart'; 2 | import 'package:bull_signal/Services/notificationHandler.dart'; 3 | import 'package:bull_signal/Utils/consts.dart'; 4 | import 'package:bull_signal/tools/custom_toast.dart'; 5 | import 'package:bull_signal/tools/loading.dart'; 6 | import 'package:cached_network_image/cached_network_image.dart'; 7 | import 'package:cloud_firestore/cloud_firestore.dart'; 8 | import 'package:flutter/material.dart'; 9 | // import 'package:timeago/timeago.dart' as timeago; 10 | import 'package:uuid/uuid.dart'; 11 | 12 | class CommentsNChatAdmin extends StatefulWidget { 13 | // final String? postId; 14 | // final String? postOwnerId; 15 | final String? chatId; 16 | final String? heroMsg; 17 | // final bool? isParent; 18 | final String? chatNotificationToken; 19 | // final String userName; 20 | CommentsNChatAdmin({ 21 | // this.postId, 22 | // this.postMediaUrl, 23 | // this.postOwnerId, 24 | required this.chatId, 25 | // required this.isParent, 26 | this.heroMsg, 27 | // @required this.isPostComment, 28 | required this.chatNotificationToken, 29 | // @required this.isProductComment 30 | }); 31 | @override 32 | CommentsNChatAdminState createState() => CommentsNChatAdminState(); 33 | } 34 | 35 | TextEditingController _commentNMessagesController = TextEditingController(); 36 | 37 | class CommentsNChatAdminState extends State { 38 | // final String? postId; 39 | // final String? postOwnerId; 40 | // final bool? isComment; 41 | // final String userName; 42 | // CommentsNChatState({ 43 | // required this.postId, 44 | // required this.postOwnerId, 45 | // required this.isComment, 46 | 47 | // }); 48 | List allAdmins = []; 49 | String? chatHeadId; 50 | List commentsListGlobal = []; 51 | 52 | getAdmins() async { 53 | QuerySnapshot snapshots = 54 | await userRef.where('isAdmin', isEqualTo: true).get(); 55 | snapshots.docs.forEach((e) { 56 | allAdmins.add(AppUserModel.fromDocument(e)); 57 | }); 58 | } 59 | 60 | @override 61 | initState() { 62 | super.initState(); 63 | if (mounted) { 64 | setState(() { 65 | chatHeadId = 66 | currentUser!.isAdmin != null && currentUser!.isAdmin == true 67 | ? widget.chatId 68 | : currentUser!.id; 69 | }); 70 | } 71 | getAdmins(); 72 | } 73 | 74 | buildChat() { 75 | print(widget.chatId); 76 | return StreamBuilder( 77 | stream: 78 | // currentUser!.isAdmin! 79 | // ? chatRoomRef 80 | // .doc(currentUser!.isAdmin != null && currentUser!.isAdmin == true 81 | // ? widget.chatId 82 | // : currentUser!.id) 83 | // .collection("chats") 84 | // .snapshots() 85 | // : 86 | chatRoomRef 87 | .doc(currentUser!.isAdmin != null && currentUser!.isAdmin == true 88 | ? widget.chatId 89 | : currentUser!.id) 90 | .collection("chats") 91 | .orderBy("timestamp", descending: false) 92 | .snapshots(), 93 | builder: (context, snapshot) { 94 | if (!snapshot.hasData) { 95 | return const LoadingIndicator(); 96 | } 97 | 98 | List chatMessages = []; 99 | snapshot.data!.docs.forEach((DocumentSnapshot doc) { 100 | chatMessages.add(CommentsNMessages.fromDocument(doc)); 101 | }); 102 | print(chatMessages); 103 | return ListView( 104 | children: chatMessages, 105 | ); 106 | }, 107 | ); 108 | } 109 | 110 | addChatMessage() { 111 | String commentId = const Uuid().v1(); 112 | if (_commentNMessagesController.text.trim().length > 1) { 113 | chatRoomRef 114 | .doc(currentUser!.isAdmin != null && currentUser!.isAdmin == true 115 | ? widget.chatId 116 | : currentUser!.id) 117 | .collection("chats") 118 | .doc(commentId) 119 | .set({ 120 | "userName": currentUser!.name, 121 | "userId": currentUser!.id, 122 | "androidNotificationToken": currentUser!.androidNotificationToken, 123 | "comment": _commentNMessagesController.text, 124 | "timestamp": DateTime.now(), 125 | // "avatarUrl": currentUser!.imageUrl, 126 | "commentId": commentId, 127 | }); 128 | currentUser!.isAdmin! 129 | ? null 130 | : chatListRef 131 | .doc(currentUser!.isAdmin! ? widget.chatId : currentUser!.id) 132 | .set({ 133 | "userName": currentUser!.name, 134 | "userId": currentUser!.id, 135 | "comment": _commentNMessagesController.text, 136 | "timestamp": DateTime.now(), 137 | "androidNotificationToken": widget.chatNotificationToken ?? 138 | currentUser!.androidNotificationToken, 139 | }); 140 | // sendNotificationToAdmin( 141 | // type: "adminChats", title: "Admin Chats", isAdminChat: true); 142 | // if (isAdmin) { 143 | // activityFeedRef.doc(widget.chatId).collection('feedItems').add({ 144 | // "type": "adminChats", 145 | // "commentData": _commentNMessagesController.text, 146 | // "userName": currentUser.userName, 147 | // "userId": currentUser.id, 148 | // "userProfileImg": currentUser.photoUrl, 149 | // "postId": widget.chatId, 150 | // "mediaUrl": postMediaUrl, 151 | // "timestamp": timestamp, 152 | // }); 153 | sendAndRetrieveMessage( 154 | token: widget.chatNotificationToken!, 155 | message: _commentNMessagesController.text, 156 | title: "Admin_Chats", 157 | context: context); 158 | // } 159 | 160 | } else { 161 | errorToast(message: "Message field shouldn't be left Empty"); 162 | } 163 | _commentNMessagesController.clear(); 164 | } 165 | 166 | @override 167 | Widget build(BuildContext context) { 168 | return Scaffold( 169 | appBar: AppBar( 170 | centerTitle: true, 171 | elevation: 0, 172 | backgroundColor: Colors.transparent, 173 | title: Text( 174 | currentUser!.isAdmin! ? "Manage Queries" : "Contact Admin", 175 | // style: TextStyle(color: Colors.black), 176 | ), 177 | ), 178 | body: Padding( 179 | padding: const EdgeInsets.only(bottom: 20.0), 180 | child: Column( 181 | children: [ 182 | Expanded( 183 | child: buildChat(), 184 | ), 185 | const Divider(), 186 | ListTile( 187 | title: TextFormField( 188 | controller: _commentNMessagesController, 189 | decoration: const InputDecoration( 190 | hintText: "Write a message...", 191 | ), 192 | ), 193 | trailing: IconButton( 194 | onPressed: addChatMessage, 195 | icon: const Icon( 196 | Icons.send, 197 | size: 40.0, 198 | ), 199 | ), 200 | ), 201 | // SizedBox( 202 | // height: 50, 203 | // ), 204 | ], 205 | ), 206 | ), 207 | ); 208 | } 209 | } 210 | 211 | class CommentsNMessages extends StatefulWidget { 212 | final String? userName; 213 | final String? userId; 214 | final String? avatarUrl; 215 | final String? comment; 216 | final Timestamp? timestamp; 217 | final String? commentId; 218 | final String? androidNotificationToken; 219 | const CommentsNMessages({Key? key, 220 | this.userName, 221 | this.userId, 222 | this.avatarUrl, 223 | this.comment, 224 | this.timestamp, 225 | this.commentId, 226 | this.androidNotificationToken, 227 | }) : super(key: key); 228 | factory CommentsNMessages.fromDocument(doc) { 229 | return CommentsNMessages( 230 | // avatarUrl: doc['avatarUrl'], 231 | comment: doc.data()['comment'], 232 | timestamp: doc.data()['timestamp'], 233 | userId: doc.data()['userId'], 234 | userName: doc.data()['userName'], 235 | commentId: doc.data()["commentId"], 236 | androidNotificationToken: doc["androidNotificationToken"], 237 | ); 238 | } 239 | 240 | @override 241 | _CommentsNMessagesState createState() => _CommentsNMessagesState(); 242 | } 243 | 244 | class _CommentsNMessagesState extends State { 245 | @override 246 | Widget build(BuildContext context) { 247 | return Padding( 248 | padding: const EdgeInsets.only(bottom: 12, right: 12, left: 12), 249 | child: buildMessageBubble(context), 250 | ); 251 | } 252 | 253 | buildMessageBubble(BuildContext context) { 254 | bool isMe = currentUser!.id == widget.userId; 255 | return Padding( 256 | padding: const EdgeInsets.only(left: 14.0, right: 14.0), 257 | child: Container( 258 | width: MediaQuery.of(context).size.width * 0.5, 259 | decoration: BoxDecoration( 260 | color: isMe ? Colors.orange : Colors.brown, 261 | borderRadius: isMe 262 | ? const BorderRadius.only( 263 | bottomLeft: Radius.circular(20), 264 | bottomRight: Radius.circular(20), 265 | topLeft: Radius.circular(20), 266 | ) 267 | : const BorderRadius.only( 268 | bottomLeft: Radius.circular(20), 269 | bottomRight: Radius.circular(20), 270 | topRight: Radius.circular(20), 271 | ), 272 | ), 273 | child: Padding( 274 | padding: const EdgeInsets.all(12.0), 275 | child: Column( 276 | crossAxisAlignment: CrossAxisAlignment.start, 277 | mainAxisAlignment: MainAxisAlignment.start, 278 | children: [ 279 | Row( 280 | crossAxisAlignment: CrossAxisAlignment.center, 281 | children: [ 282 | widget.avatarUrl != null && widget.avatarUrl != '' 283 | ? CircleAvatar( 284 | backgroundImage: 285 | CachedNetworkImageProvider(widget.avatarUrl!), 286 | ) 287 | : const CircleAvatar(backgroundImage: AssetImage(logo)), 288 | const SizedBox( 289 | width: 8, 290 | ), 291 | Expanded( 292 | child: Column( 293 | // crossAxisAlignment: CrossAxisAlignment.start, 294 | // mainAxisAlignment: MainAxisAlignment.start, 295 | // mainAxisSize: MainAxisSize.min, 296 | children: [ 297 | Row( 298 | crossAxisAlignment: CrossAxisAlignment.start, 299 | mainAxisAlignment: MainAxisAlignment.start, 300 | children: [ 301 | Text("${widget.userName} : ", 302 | style: const TextStyle( 303 | fontWeight: FontWeight.bold, 304 | fontSize: 14.0, 305 | color: Colors.white)), 306 | Flexible( 307 | child: Text( 308 | "${widget.comment}", 309 | style: const TextStyle( 310 | fontSize: 14.0, color: Colors.white), 311 | ), 312 | ), 313 | ], 314 | ), 315 | // Text( 316 | // timeago.format(widget.timestamp!.toDate()), 317 | // style: TextStyle(color: Colors.black54, fontSize: 12), 318 | // ), 319 | ], 320 | ), 321 | ) 322 | ], 323 | ), 324 | ], 325 | ), 326 | ), 327 | ), 328 | ); 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /lib/announcements/addAnnouncements.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:bull_signal/Database/database.dart'; 3 | import 'package:bull_signal/Screens/webview.dart'; 4 | import 'package:bull_signal/Services/firebase_api.dart'; 5 | import 'package:bull_signal/Services/notificationHandler.dart'; 6 | import 'package:bull_signal/tools/custom_toast.dart'; 7 | import 'package:bull_signal/tools/loading.dart'; 8 | import 'package:firebase_storage/firebase_storage.dart'; 9 | import 'package:flutter/material.dart'; 10 | import 'package:uuid/uuid.dart'; 11 | import 'package:image/image.dart' as Im; 12 | import 'package:path_provider/path_provider.dart'; 13 | import 'package:image_picker/image_picker.dart'; 14 | 15 | class AddAnnouncements extends StatefulWidget { 16 | @override 17 | _AddAnnouncementsState createState() => _AddAnnouncementsState(); 18 | } 19 | 20 | class _AddAnnouncementsState extends State { 21 | final TextEditingController _titleTextController = TextEditingController(); 22 | String postId = const Uuid().v4(); 23 | bool isUploading = false; 24 | final TextEditingController _descriptionTextController = 25 | TextEditingController(); 26 | File? file; 27 | bool _isLoading = false; 28 | final _textFormkey = GlobalKey(); 29 | ScrollController _scrollController = ScrollController(); 30 | @override 31 | void initState() { 32 | super.initState(); 33 | } 34 | 35 | @override 36 | Widget build(BuildContext context) { 37 | return SafeArea( 38 | child: Stack( 39 | children: [ 40 | Scaffold( 41 | appBar: AppBar( 42 | title: const Text( 43 | "Add Announcements", 44 | style: TextStyle(fontSize: 18), 45 | ), 46 | backgroundColor: Colors.transparent, 47 | centerTitle: true, 48 | elevation: 0, 49 | actions: [ 50 | Padding( 51 | padding: const EdgeInsets.all(10.0), 52 | // ignore: deprecated_member_use 53 | child: RaisedButton.icon( 54 | onPressed: () { 55 | buildMediaDialog(context); 56 | }, 57 | icon: const Icon( 58 | Icons.add, 59 | size: 20.0, 60 | ), 61 | shape: const RoundedRectangleBorder( 62 | borderRadius: BorderRadius.all(Radius.circular(8.0))), 63 | label: const Text( 64 | 'Add Media', 65 | style: TextStyle(fontSize: 8.0), 66 | ), 67 | ), 68 | ) 69 | ], 70 | ), 71 | body: SingleChildScrollView( 72 | controller: _scrollController, 73 | child: Form( 74 | key: _textFormkey, 75 | child: Padding( 76 | padding: const EdgeInsets.all(16.0), 77 | child: Column( 78 | children: [ 79 | Padding( 80 | padding: const EdgeInsets.all(8.0), 81 | child: TextFormField( 82 | controller: _titleTextController, 83 | validator: (val) => val!.trim().length < 3 84 | ? 'Announcement Title Too Short' 85 | : null, 86 | decoration: const InputDecoration( 87 | // border: InputBorder.none, 88 | hintText: "Enter title of announcement", 89 | labelText: "Title"), 90 | ), 91 | ), 92 | const SizedBox( 93 | height: 25.0, 94 | ), 95 | Padding( 96 | padding: const EdgeInsets.all(8.0), 97 | child: TextFormField( 98 | controller: _descriptionTextController, 99 | validator: (val) => val!.trim().length < 3 100 | ? 'Announcement Description Title Too Short' 101 | : null, 102 | decoration: const InputDecoration( 103 | // border: InputBorder.none, 104 | hintText: "Enter Description of announcement", 105 | labelText: "Description"), 106 | ), 107 | ), 108 | this.file == null 109 | ? Container( 110 | margin: EdgeInsets.all(10), 111 | height: 200, 112 | width: 200, 113 | decoration: BoxDecoration( 114 | border: Border.all(width: 1), 115 | borderRadius: BorderRadius.circular(4), 116 | color: Theme.of(context).backgroundColor, 117 | ), 118 | ) 119 | : Container( 120 | margin: EdgeInsets.all(10), 121 | height: 200, 122 | width: 200, 123 | child: Container( 124 | height: 200, 125 | // width: 200, 126 | decoration: BoxDecoration( 127 | // borderRadius: BorderRadius.only( 128 | // topLeft: const Radius.circular(40.0), 129 | // ), 130 | color: Theme.of(context).backgroundColor, 131 | ), 132 | child: Image.file( 133 | this.file!, 134 | fit: BoxFit.contain, 135 | alignment: Alignment.center, 136 | ), 137 | ), 138 | ), 139 | const SizedBox( 140 | height: 25.0, 141 | ), 142 | GestureDetector( 143 | onTap: () => 144 | Navigator.of(context).push(MaterialPageRoute( 145 | builder: (context) => const Webview(), 146 | )), 147 | child: Padding( 148 | padding: const EdgeInsets.all(24.0), 149 | child: Row( 150 | children: const [ 151 | Icon( 152 | Icons.auto_graph_outlined, 153 | ), 154 | Text(" Open TradingView"), 155 | ], 156 | ), 157 | ), 158 | ), 159 | GestureDetector( 160 | onTap: () => handleSubmit(), 161 | child: Padding( 162 | padding: const EdgeInsets.all(24.0), 163 | child: isUploading 164 | ? const LoadingIndicator() 165 | : Row( 166 | children: const [ 167 | Icon(Icons.send_outlined), 168 | Text(" Send Announcement"), 169 | ], 170 | ), 171 | ), 172 | ) 173 | ], 174 | ), 175 | ), 176 | ), 177 | ), 178 | ), 179 | _isLoading ? const LoadingIndicator() : Container() 180 | ], 181 | ), 182 | ); 183 | } 184 | 185 | compressImage() async { 186 | final tempDir = await getTemporaryDirectory(); 187 | final path = tempDir.path; 188 | Im.Image? imageFile = Im.decodeImage(file!.readAsBytesSync()); 189 | final compressedImageFile = File('$path/img_$postId.jpg') 190 | ..writeAsBytesSync(Im.encodeJpg(imageFile!, quality: 85)); 191 | setState(() { 192 | file = compressedImageFile; 193 | }); 194 | } 195 | 196 | handleImageFromGallery() async { 197 | Navigator.pop(context); 198 | var picker = await ImagePicker().getImage(source: ImageSource.gallery); 199 | File file; 200 | file = File(picker!.path); 201 | setState(() { 202 | this.file = file; 203 | }); 204 | } 205 | 206 | Future uploadImage(imageFile) async { 207 | Reference firebaseStorageRef = 208 | FirebaseStorage.instance.ref().child('posts/$postId.jpg'); 209 | UploadTask uploadTask = firebaseStorageRef.putFile(imageFile); 210 | // storageRef.child("post_$postId.jpg").putFile(imageFile); 211 | // TaskSnapshot storageSnap = await uploadTask.onComplete; 212 | // String downloadUrl = await storageSnap.ref.getDownloadURL(); 213 | // return downloadUrl; 214 | 215 | String? downloadUrl; 216 | await uploadTask.whenComplete(() async { 217 | downloadUrl = await firebaseStorageRef.getDownloadURL(); 218 | }); 219 | // uploadTask.then((res) async { 220 | // downloadUrl = await res.ref.getDownloadURL(); 221 | // }); 222 | return downloadUrl!; 223 | } 224 | 225 | createPostInFirestore({ 226 | final String? announcementTitle, 227 | final String? description, 228 | final String? imageUrl, 229 | final String? eachUserToken, 230 | // final String? eachUserId, 231 | }) async { 232 | return FirebaseApi().addAnnouncements( 233 | description: description!, 234 | imageUrl: imageUrl!, 235 | eachUserToken: eachUserToken!, 236 | // eachUserId: eachUserId!, 237 | announcementTitle: announcementTitle!, 238 | postId: postId); 239 | } 240 | 241 | handleSubmit() async { 242 | final _form = _textFormkey.currentState; 243 | if (_form!.validate()) { 244 | setState(() { 245 | isUploading = true; 246 | }); 247 | _scrollController.animateTo(0.0, 248 | duration: const Duration(milliseconds: 600), curve: Curves.easeOut); 249 | // ignore: unnecessary_statements 250 | file != null ? await compressImage() : null; 251 | String imageUrl = file != null 252 | ? await uploadImage(file).catchError((onError) { 253 | isUploading = false; 254 | errorToast(message: "Couldn't connect to servers!!"); 255 | }) 256 | : ""; 257 | 258 | await createPostInFirestore( 259 | announcementTitle: _titleTextController.text, 260 | imageUrl: imageUrl, 261 | eachUserToken: _titleTextController.text, 262 | description: _descriptionTextController.text); 263 | sendAndRetrieveMessage( 264 | token: _titleTextController.text, 265 | message: _descriptionTextController.text, 266 | context: context, 267 | imageUrl: imageUrl, 268 | title: _titleTextController.text); 269 | 270 | _descriptionTextController.clear(); 271 | _titleTextController.clear(); 272 | setState(() { 273 | isUploading = false; 274 | postId = const Uuid().v4(); 275 | }); 276 | 277 | Navigator.pop(context); 278 | } 279 | successToast(message: "Announcement Added"); 280 | } 281 | 282 | buildMediaDialog(BuildContext parentContext) { 283 | return showDialog( 284 | context: parentContext, 285 | builder: (context) { 286 | return SimpleDialog( 287 | children: [ 288 | SimpleDialogOption( 289 | onPressed: () { 290 | //Navigator.pop(context); 291 | handleImageFromGallery(); 292 | }, 293 | child: Padding( 294 | padding: const EdgeInsets.all(8.0), 295 | child: Row( 296 | mainAxisAlignment: MainAxisAlignment.center, 297 | children: const [ 298 | Icon(Icons.image), 299 | SizedBox( 300 | width: 5, 301 | ), 302 | Text( 303 | 'Upload Image', 304 | ), 305 | ], 306 | ), 307 | ), 308 | ), 309 | SimpleDialogOption( 310 | onPressed: () => Navigator.pop(context), 311 | child: Padding( 312 | padding: const EdgeInsets.all(8.0), 313 | child: Row( 314 | children: const [ 315 | Icon(Icons.exit_to_app), 316 | SizedBox( 317 | width: 5, 318 | ), 319 | Text('Cancel'), 320 | ], 321 | ), 322 | ), 323 | ) 324 | ], 325 | ); 326 | }); 327 | } 328 | } 329 | -------------------------------------------------------------------------------- /lib/Screens/user_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:bull_signal/Screens/Admin/allUsers.dart'; 2 | import 'package:bull_signal/Utils/consts.dart'; 3 | import 'package:bull_signal/tools/loading.dart'; 4 | import 'package:cached_network_image/cached_network_image.dart'; 5 | import 'package:cloud_firestore/cloud_firestore.dart'; 6 | import 'package:firebase_auth/firebase_auth.dart'; 7 | import 'package:flutter/material.dart'; 8 | 9 | import 'Admin/commentsNChatAdmin.dart'; 10 | 11 | class UserInfoScreen extends StatefulWidget { 12 | @override 13 | _UserInfoScreenState createState() => _UserInfoScreenState(); 14 | } 15 | 16 | class _UserInfoScreenState extends State { 17 | ScrollController? _scrollController; 18 | var top = 0.0; 19 | final FirebaseAuth _auth = FirebaseAuth.instance; 20 | // String? _uid; 21 | // String? _name; 22 | // String? _email; 23 | // String? _joinedAt; 24 | // String? _userImageUrl; 25 | // int? _phoneNumber; 26 | bool isLoading = false; 27 | @override 28 | void initState() { 29 | super.initState(); 30 | _scrollController = ScrollController(); 31 | _scrollController!.addListener(() { 32 | setState(() {}); 33 | }); 34 | // getData(); 35 | } 36 | 37 | // void getData() async { 38 | // setState(() { 39 | // isLoading = true; 40 | // }); 41 | // User user = DatabaseMethods().fetchUserInfoFromFirebase(uid: uid); 42 | // _uid = user.uid; 43 | 44 | // print('user.displayName ${user.displayName}'); 45 | // print('user.photoURL ${user.photoURL}'); 46 | // DocumentSnapshot>? userDoc = user.isAnonymous 47 | // ? null 48 | // : await FirebaseFirestore.instance.collection('users').doc(_uid).get(); 49 | // // .then((value) { 50 | // // if (user.isAnonymous) { 51 | // // userDoc = null; 52 | // // } else { 53 | // // userDoc = value; 54 | // // } 55 | // // }); 56 | // if (userDoc == null) { 57 | // return; 58 | // } else { 59 | // setState(() { 60 | // currentUser = AppUserModel.fromDocument(userDoc); 61 | // _name = userDoc.get('name'); 62 | // _email = user.email!; 63 | // _joinedAt = userDoc.get('joinedAt'); 64 | // _phoneNumber = userDoc.get('phoneNumber'); 65 | // _userImageUrl = userDoc.get('imageUrl'); 66 | // isLoading = false; 67 | // }); 68 | // } 69 | 70 | // // print("name $_name"); 71 | // } 72 | 73 | @override 74 | Widget build(BuildContext context) { 75 | // final themeChange = Provider.of(context); 76 | // final notificationChange = Provider.of(context); 77 | 78 | return SafeArea( 79 | child: Scaffold( 80 | body: isLoading 81 | ? const LoadingIndicator() 82 | : Stack( 83 | children: [ 84 | CustomScrollView( 85 | controller: _scrollController, 86 | slivers: [ 87 | SliverAppBar( 88 | // leading: Icon(Icons.ac_unit_outlined), 89 | // automaticallyImplyLeading: false, 90 | elevation: 0, 91 | expandedHeight: 250, 92 | pinned: true, 93 | flexibleSpace: LayoutBuilder(builder: 94 | (BuildContext context, BoxConstraints constraints) { 95 | top = constraints.biggest.height; 96 | 97 | return Container( 98 | decoration: const BoxDecoration( 99 | // gradient: LinearGradient( 100 | // colors: [ 101 | // ColorsConsts.starterColor, 102 | // ColorsConsts.endColor, 103 | // ], 104 | // begin: const FractionalOffset(0.0, 0.0), 105 | // end: const FractionalOffset(1.0, 0.0), 106 | // stops: [0.0, 1.0], 107 | // tileMode: TileMode.clamp), 108 | ), 109 | child: FlexibleSpaceBar( 110 | // collapseMode: CollapseMode.parallax, 111 | centerTitle: true, 112 | title: AnimatedOpacity( 113 | duration: const Duration(milliseconds: 300), 114 | opacity: top <= 110.0 ? 1.0 : 0, 115 | child: Row( 116 | children: [ 117 | const SizedBox( 118 | width: 12, 119 | ), 120 | Container( 121 | height: kToolbarHeight / 1.8, 122 | width: kToolbarHeight / 1.8, 123 | decoration: const BoxDecoration( 124 | boxShadow: [ 125 | BoxShadow( 126 | color: Colors.white, 127 | blurRadius: 1.0, 128 | ), 129 | ], 130 | shape: BoxShape.circle, 131 | image: DecorationImage( 132 | fit: BoxFit.fill, 133 | image: NetworkImage( 134 | 'https://t3.ftcdn.net/jpg/01/83/55/76/240_F_183557656_DRcvOesmfDl5BIyhPKrcWANFKy2964i9.jpg'), 135 | ), 136 | ), 137 | ), 138 | const SizedBox( 139 | width: 12, 140 | ), 141 | Text( 142 | // 'top.toString()', 143 | currentUser!.name! == null 144 | ? 'Guest' 145 | : currentUser!.name!, 146 | style: const TextStyle( 147 | fontSize: 20.0, color: Colors.white), 148 | ), 149 | ], 150 | ), 151 | ), 152 | background: Column( 153 | children: [ 154 | Text( 155 | "Settings", 156 | style: titleTextStyle(color: Colors.white), 157 | ), 158 | const CircleAvatar( 159 | maxRadius: 50, 160 | minRadius: 30, 161 | backgroundImage: CachedNetworkImageProvider( 162 | 'https://t3.ftcdn.net/jpg/01/83/55/76/240_F_183557656_DRcvOesmfDl5BIyhPKrcWANFKy2964i9.jpg'), 163 | ), 164 | Text( 165 | currentUser!.name! == null 166 | ? 'Guest' 167 | : currentUser!.name!, 168 | style: titleTextStyle( 169 | fontSize: 20, 170 | color: Theme.of(context).dividerColor), 171 | ), 172 | 173 | // Container( 174 | // margin: EdgeInsets.only(top: 8), 175 | // padding: EdgeInsets.all(8), 176 | // decoration: BoxDecoration( 177 | // color: Colors.teal, 178 | // borderRadius: 179 | // BorderRadius.circular(20)), 180 | // child: Text("Edit Profile"), 181 | // ), 182 | ], 183 | ), 184 | ), 185 | ); 186 | }), 187 | ), 188 | SliverToBoxAdapter( 189 | child: Column( 190 | mainAxisAlignment: MainAxisAlignment.center, 191 | crossAxisAlignment: CrossAxisAlignment.start, 192 | children: [ 193 | currentUser!.isAdmin! 194 | ? Material( 195 | color: Colors.transparent, 196 | child: InkWell( 197 | onTap: () => Navigator.of(context) 198 | .push(MaterialPageRoute( 199 | builder: (context) => 200 | const UserNSearch(), 201 | )), 202 | splashColor: Colors.red, 203 | child: const ListTile( 204 | title: Text('All Users'), 205 | trailing: 206 | Icon(Icons.chevron_right_rounded), 207 | leading: Icon(Icons.all_inbox_outlined), 208 | ), 209 | ), 210 | ) 211 | : const SizedBox(), 212 | currentUser!.isAdmin! 213 | ? Container() 214 | : Material( 215 | color: Colors.transparent, 216 | child: InkWell( 217 | onTap: () => Navigator.of(context) 218 | .push(MaterialPageRoute( 219 | builder: (context) => 220 | CommentsNChatAdmin( 221 | chatId: currentUser!.id, 222 | chatNotificationToken: currentUser! 223 | .androidNotificationToken, 224 | ), 225 | )), 226 | splashColor: Colors.red, 227 | child: const ListTile( 228 | title: Text('Report a Problem'), 229 | trailing: 230 | Icon(Icons.chevron_right_rounded), 231 | leading: Icon(Icons.flag), 232 | ), 233 | ), 234 | ), 235 | Material( 236 | color: Colors.transparent, 237 | child: InkWell( 238 | splashColor: Theme.of(context).splashColor, 239 | child: ListTile( 240 | onTap: () async { 241 | // Navigator.canPop(context)? Navigator.pop(context):null; 242 | showDialog( 243 | context: context, 244 | builder: (BuildContext ctx) { 245 | return AlertDialog( 246 | title: Row( 247 | children: [ 248 | Padding( 249 | padding: 250 | const EdgeInsets.only( 251 | right: 6.0), 252 | child: Image.network( 253 | 'https://image.flaticon.com/icons/png/128/1828/1828304.png', 254 | height: 20, 255 | width: 20, 256 | ), 257 | ), 258 | const Padding( 259 | padding: EdgeInsets.all(8.0), 260 | child: Text('Sign out'), 261 | ), 262 | ], 263 | ), 264 | content: const Text( 265 | 'Do you wanna Sign out?'), 266 | actions: [ 267 | TextButton( 268 | onPressed: () async { 269 | Navigator.pop(context); 270 | }, 271 | child: const Text('Cancel')), 272 | TextButton( 273 | onPressed: () async { 274 | await _auth.signOut().then( 275 | (value) => 276 | Navigator.pop( 277 | context)); 278 | }, 279 | child: const Text( 280 | 'Ok', 281 | style: const TextStyle( 282 | color: Colors.red), 283 | )) 284 | ], 285 | ); 286 | }); 287 | }, 288 | title: const Text('Logout'), 289 | leading: 290 | const Icon(Icons.exit_to_app_rounded), 291 | ), 292 | ), 293 | ), 294 | ], 295 | ), 296 | ) 297 | ], 298 | ), 299 | // _buildFab() 300 | ], 301 | ), 302 | ), 303 | ); 304 | } 305 | 306 | Widget _buildFab() { 307 | //starting fab position 308 | final double defaultTopMargin = 200.0 - 4.0; 309 | //pixels from top where scaling should start 310 | final double scaleStart = 160.0; 311 | //pixels from top where scaling should end 312 | final double scaleEnd = scaleStart / 2; 313 | 314 | double top = defaultTopMargin; 315 | double scale = 1.0; 316 | if (_scrollController!.hasClients) { 317 | double offset = _scrollController!.offset; 318 | top -= offset; 319 | if (offset < defaultTopMargin - scaleStart) { 320 | //offset small => don't scale down 321 | 322 | scale = 1.0; 323 | } else if (offset < defaultTopMargin - scaleEnd) { 324 | //offset between scaleStart and scaleEnd => scale down 325 | 326 | scale = (defaultTopMargin - scaleEnd - offset) / scaleEnd; 327 | } else { 328 | //offset passed scaleEnd => hide fab 329 | scale = 0.0; 330 | } 331 | } 332 | 333 | return Positioned( 334 | top: top, 335 | right: 16.0, 336 | child: Transform( 337 | transform: Matrix4.identity()..scale(scale), 338 | alignment: Alignment.center, 339 | child: FloatingActionButton( 340 | backgroundColor: Colors.purple, 341 | heroTag: "btn1", 342 | onPressed: () {}, 343 | child: const Icon(Icons.camera_alt_outlined), 344 | ), 345 | ), 346 | ); 347 | } 348 | 349 | List _userTileIcons = [ 350 | Icons.email, 351 | Icons.phone, 352 | Icons.local_shipping, 353 | Icons.watch_later, 354 | Icons.exit_to_app_rounded 355 | ]; 356 | 357 | Widget userListTile( 358 | String title, String subTitle, int index, BuildContext context) { 359 | return ListTile( 360 | title: Text(title), 361 | subtitle: Text(subTitle), 362 | leading: Icon(_userTileIcons[index]), 363 | ); 364 | } 365 | 366 | Widget userTitle({required String title}) { 367 | return Container( 368 | width: double.maxFinite, 369 | color: Theme.of(context).primaryColor, 370 | padding: const EdgeInsets.all(8.0), 371 | child: Text( 372 | title, 373 | style: const TextStyle( 374 | fontWeight: FontWeight.bold, 375 | fontSize: 23, 376 | ), 377 | ), 378 | ); 379 | } 380 | } 381 | -------------------------------------------------------------------------------- /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: "3.1.9" 11 | args: 12 | dependency: transitive 13 | description: 14 | name: args 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.3.0" 18 | async: 19 | dependency: transitive 20 | description: 21 | name: async 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "2.8.2" 25 | boolean_selector: 26 | dependency: transitive 27 | description: 28 | name: boolean_selector 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "2.1.0" 32 | cached_network_image: 33 | dependency: "direct main" 34 | description: 35 | name: cached_network_image 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "3.2.0" 39 | cached_network_image_platform_interface: 40 | dependency: transitive 41 | description: 42 | name: cached_network_image_platform_interface 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.0.0" 46 | cached_network_image_web: 47 | dependency: transitive 48 | description: 49 | name: cached_network_image_web 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.0.1" 53 | characters: 54 | dependency: transitive 55 | description: 56 | name: characters 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "1.2.0" 60 | charcode: 61 | dependency: transitive 62 | description: 63 | name: charcode 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.3.1" 67 | clock: 68 | dependency: transitive 69 | description: 70 | name: clock 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "1.1.0" 74 | cloud_firestore: 75 | dependency: "direct main" 76 | description: 77 | name: cloud_firestore 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "3.1.7" 81 | cloud_firestore_platform_interface: 82 | dependency: transitive 83 | description: 84 | name: cloud_firestore_platform_interface 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "5.4.12" 88 | cloud_firestore_web: 89 | dependency: transitive 90 | description: 91 | name: cloud_firestore_web 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "2.6.7" 95 | collection: 96 | dependency: transitive 97 | description: 98 | name: collection 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "1.15.0" 102 | cross_file: 103 | dependency: transitive 104 | description: 105 | name: cross_file 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "0.3.2" 109 | crypto: 110 | dependency: transitive 111 | description: 112 | name: crypto 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "3.0.1" 116 | cupertino_icons: 117 | dependency: "direct main" 118 | description: 119 | name: cupertino_icons 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "1.0.4" 123 | dbus: 124 | dependency: transitive 125 | description: 126 | name: dbus 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "0.6.8" 130 | fake_async: 131 | dependency: transitive 132 | description: 133 | name: fake_async 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "1.2.0" 137 | ffi: 138 | dependency: transitive 139 | description: 140 | name: ffi 141 | url: "https://pub.dartlang.org" 142 | source: hosted 143 | version: "1.1.2" 144 | file: 145 | dependency: transitive 146 | description: 147 | name: file 148 | url: "https://pub.dartlang.org" 149 | source: hosted 150 | version: "6.1.2" 151 | firebase_auth: 152 | dependency: "direct main" 153 | description: 154 | name: firebase_auth 155 | url: "https://pub.dartlang.org" 156 | source: hosted 157 | version: "3.3.6" 158 | firebase_auth_platform_interface: 159 | dependency: transitive 160 | description: 161 | name: firebase_auth_platform_interface 162 | url: "https://pub.dartlang.org" 163 | source: hosted 164 | version: "6.1.11" 165 | firebase_auth_web: 166 | dependency: transitive 167 | description: 168 | name: firebase_auth_web 169 | url: "https://pub.dartlang.org" 170 | source: hosted 171 | version: "3.3.7" 172 | firebase_core: 173 | dependency: "direct main" 174 | description: 175 | name: firebase_core 176 | url: "https://pub.dartlang.org" 177 | source: hosted 178 | version: "1.12.0" 179 | firebase_core_platform_interface: 180 | dependency: transitive 181 | description: 182 | name: firebase_core_platform_interface 183 | url: "https://pub.dartlang.org" 184 | source: hosted 185 | version: "4.2.4" 186 | firebase_core_web: 187 | dependency: transitive 188 | description: 189 | name: firebase_core_web 190 | url: "https://pub.dartlang.org" 191 | source: hosted 192 | version: "1.5.4" 193 | firebase_messaging: 194 | dependency: "direct main" 195 | description: 196 | name: firebase_messaging 197 | url: "https://pub.dartlang.org" 198 | source: hosted 199 | version: "11.2.6" 200 | firebase_messaging_platform_interface: 201 | dependency: transitive 202 | description: 203 | name: firebase_messaging_platform_interface 204 | url: "https://pub.dartlang.org" 205 | source: hosted 206 | version: "3.1.6" 207 | firebase_messaging_web: 208 | dependency: transitive 209 | description: 210 | name: firebase_messaging_web 211 | url: "https://pub.dartlang.org" 212 | source: hosted 213 | version: "2.2.7" 214 | firebase_storage: 215 | dependency: "direct main" 216 | description: 217 | name: firebase_storage 218 | url: "https://pub.dartlang.org" 219 | source: hosted 220 | version: "10.2.6" 221 | firebase_storage_platform_interface: 222 | dependency: transitive 223 | description: 224 | name: firebase_storage_platform_interface 225 | url: "https://pub.dartlang.org" 226 | source: hosted 227 | version: "4.0.13" 228 | firebase_storage_web: 229 | dependency: transitive 230 | description: 231 | name: firebase_storage_web 232 | url: "https://pub.dartlang.org" 233 | source: hosted 234 | version: "3.2.7" 235 | flutter: 236 | dependency: "direct main" 237 | description: flutter 238 | source: sdk 239 | version: "0.0.0" 240 | flutter_blurhash: 241 | dependency: transitive 242 | description: 243 | name: flutter_blurhash 244 | url: "https://pub.dartlang.org" 245 | source: hosted 246 | version: "0.6.0" 247 | flutter_cache_manager: 248 | dependency: transitive 249 | description: 250 | name: flutter_cache_manager 251 | url: "https://pub.dartlang.org" 252 | source: hosted 253 | version: "3.3.0" 254 | flutter_lints: 255 | dependency: "direct dev" 256 | description: 257 | name: flutter_lints 258 | url: "https://pub.dartlang.org" 259 | source: hosted 260 | version: "1.0.4" 261 | flutter_local_notifications: 262 | dependency: "direct main" 263 | description: 264 | name: flutter_local_notifications 265 | url: "https://pub.dartlang.org" 266 | source: hosted 267 | version: "9.2.0" 268 | flutter_local_notifications_linux: 269 | dependency: transitive 270 | description: 271 | name: flutter_local_notifications_linux 272 | url: "https://pub.dartlang.org" 273 | source: hosted 274 | version: "0.4.1+1" 275 | flutter_local_notifications_platform_interface: 276 | dependency: transitive 277 | description: 278 | name: flutter_local_notifications_platform_interface 279 | url: "https://pub.dartlang.org" 280 | source: hosted 281 | version: "5.0.0" 282 | flutter_plugin_android_lifecycle: 283 | dependency: transitive 284 | description: 285 | name: flutter_plugin_android_lifecycle 286 | url: "https://pub.dartlang.org" 287 | source: hosted 288 | version: "2.0.5" 289 | flutter_svg: 290 | dependency: "direct main" 291 | description: 292 | name: flutter_svg 293 | url: "https://pub.dartlang.org" 294 | source: hosted 295 | version: "1.0.3" 296 | flutter_test: 297 | dependency: "direct dev" 298 | description: flutter 299 | source: sdk 300 | version: "0.0.0" 301 | flutter_web_plugins: 302 | dependency: transitive 303 | description: flutter 304 | source: sdk 305 | version: "0.0.0" 306 | flutter_webview_plugin: 307 | dependency: "direct main" 308 | description: 309 | name: flutter_webview_plugin 310 | url: "https://pub.dartlang.org" 311 | source: hosted 312 | version: "0.4.0" 313 | fluttertoast: 314 | dependency: "direct main" 315 | description: 316 | name: fluttertoast 317 | url: "https://pub.dartlang.org" 318 | source: hosted 319 | version: "8.0.8" 320 | get: 321 | dependency: transitive 322 | description: 323 | name: get 324 | url: "https://pub.dartlang.org" 325 | source: hosted 326 | version: "4.6.1" 327 | get_storage: 328 | dependency: "direct main" 329 | description: 330 | name: get_storage 331 | url: "https://pub.dartlang.org" 332 | source: hosted 333 | version: "2.0.3" 334 | http: 335 | dependency: transitive 336 | description: 337 | name: http 338 | url: "https://pub.dartlang.org" 339 | source: hosted 340 | version: "0.13.4" 341 | http_parser: 342 | dependency: transitive 343 | description: 344 | name: http_parser 345 | url: "https://pub.dartlang.org" 346 | source: hosted 347 | version: "4.0.0" 348 | image: 349 | dependency: "direct main" 350 | description: 351 | name: image 352 | url: "https://pub.dartlang.org" 353 | source: hosted 354 | version: "3.1.1" 355 | image_picker: 356 | dependency: "direct main" 357 | description: 358 | name: image_picker 359 | url: "https://pub.dartlang.org" 360 | source: hosted 361 | version: "0.8.4+5" 362 | image_picker_for_web: 363 | dependency: transitive 364 | description: 365 | name: image_picker_for_web 366 | url: "https://pub.dartlang.org" 367 | source: hosted 368 | version: "2.1.5" 369 | image_picker_platform_interface: 370 | dependency: transitive 371 | description: 372 | name: image_picker_platform_interface 373 | url: "https://pub.dartlang.org" 374 | source: hosted 375 | version: "2.4.3" 376 | intl: 377 | dependency: transitive 378 | description: 379 | name: intl 380 | url: "https://pub.dartlang.org" 381 | source: hosted 382 | version: "0.17.0" 383 | js: 384 | dependency: transitive 385 | description: 386 | name: js 387 | url: "https://pub.dartlang.org" 388 | source: hosted 389 | version: "0.6.3" 390 | lints: 391 | dependency: transitive 392 | description: 393 | name: lints 394 | url: "https://pub.dartlang.org" 395 | source: hosted 396 | version: "1.0.1" 397 | lottie: 398 | dependency: "direct main" 399 | description: 400 | name: lottie 401 | url: "https://pub.dartlang.org" 402 | source: hosted 403 | version: "1.2.1" 404 | matcher: 405 | dependency: transitive 406 | description: 407 | name: matcher 408 | url: "https://pub.dartlang.org" 409 | source: hosted 410 | version: "0.12.11" 411 | material_color_utilities: 412 | dependency: transitive 413 | description: 414 | name: material_color_utilities 415 | url: "https://pub.dartlang.org" 416 | source: hosted 417 | version: "0.1.3" 418 | meta: 419 | dependency: transitive 420 | description: 421 | name: meta 422 | url: "https://pub.dartlang.org" 423 | source: hosted 424 | version: "1.7.0" 425 | octo_image: 426 | dependency: transitive 427 | description: 428 | name: octo_image 429 | url: "https://pub.dartlang.org" 430 | source: hosted 431 | version: "1.0.1" 432 | path: 433 | dependency: transitive 434 | description: 435 | name: path 436 | url: "https://pub.dartlang.org" 437 | source: hosted 438 | version: "1.8.0" 439 | path_drawing: 440 | dependency: transitive 441 | description: 442 | name: path_drawing 443 | url: "https://pub.dartlang.org" 444 | source: hosted 445 | version: "1.0.0" 446 | path_parsing: 447 | dependency: transitive 448 | description: 449 | name: path_parsing 450 | url: "https://pub.dartlang.org" 451 | source: hosted 452 | version: "1.0.0" 453 | path_provider: 454 | dependency: "direct main" 455 | description: 456 | name: path_provider 457 | url: "https://pub.dartlang.org" 458 | source: hosted 459 | version: "2.0.8" 460 | path_provider_android: 461 | dependency: transitive 462 | description: 463 | name: path_provider_android 464 | url: "https://pub.dartlang.org" 465 | source: hosted 466 | version: "2.0.11" 467 | path_provider_ios: 468 | dependency: transitive 469 | description: 470 | name: path_provider_ios 471 | url: "https://pub.dartlang.org" 472 | source: hosted 473 | version: "2.0.7" 474 | path_provider_linux: 475 | dependency: transitive 476 | description: 477 | name: path_provider_linux 478 | url: "https://pub.dartlang.org" 479 | source: hosted 480 | version: "2.1.5" 481 | path_provider_macos: 482 | dependency: transitive 483 | description: 484 | name: path_provider_macos 485 | url: "https://pub.dartlang.org" 486 | source: hosted 487 | version: "2.0.5" 488 | path_provider_platform_interface: 489 | dependency: transitive 490 | description: 491 | name: path_provider_platform_interface 492 | url: "https://pub.dartlang.org" 493 | source: hosted 494 | version: "2.0.3" 495 | path_provider_windows: 496 | dependency: transitive 497 | description: 498 | name: path_provider_windows 499 | url: "https://pub.dartlang.org" 500 | source: hosted 501 | version: "2.0.5" 502 | pedantic: 503 | dependency: transitive 504 | description: 505 | name: pedantic 506 | url: "https://pub.dartlang.org" 507 | source: hosted 508 | version: "1.11.1" 509 | petitparser: 510 | dependency: transitive 511 | description: 512 | name: petitparser 513 | url: "https://pub.dartlang.org" 514 | source: hosted 515 | version: "4.4.0" 516 | platform: 517 | dependency: transitive 518 | description: 519 | name: platform 520 | url: "https://pub.dartlang.org" 521 | source: hosted 522 | version: "3.1.0" 523 | plugin_platform_interface: 524 | dependency: transitive 525 | description: 526 | name: plugin_platform_interface 527 | url: "https://pub.dartlang.org" 528 | source: hosted 529 | version: "2.1.2" 530 | process: 531 | dependency: transitive 532 | description: 533 | name: process 534 | url: "https://pub.dartlang.org" 535 | source: hosted 536 | version: "4.2.4" 537 | rxdart: 538 | dependency: transitive 539 | description: 540 | name: rxdart 541 | url: "https://pub.dartlang.org" 542 | source: hosted 543 | version: "0.27.3" 544 | sky_engine: 545 | dependency: transitive 546 | description: flutter 547 | source: sdk 548 | version: "0.0.99" 549 | source_span: 550 | dependency: transitive 551 | description: 552 | name: source_span 553 | url: "https://pub.dartlang.org" 554 | source: hosted 555 | version: "1.8.1" 556 | sqflite: 557 | dependency: transitive 558 | description: 559 | name: sqflite 560 | url: "https://pub.dartlang.org" 561 | source: hosted 562 | version: "2.0.2" 563 | sqflite_common: 564 | dependency: transitive 565 | description: 566 | name: sqflite_common 567 | url: "https://pub.dartlang.org" 568 | source: hosted 569 | version: "2.2.0" 570 | stack_trace: 571 | dependency: transitive 572 | description: 573 | name: stack_trace 574 | url: "https://pub.dartlang.org" 575 | source: hosted 576 | version: "1.10.0" 577 | stream_channel: 578 | dependency: transitive 579 | description: 580 | name: stream_channel 581 | url: "https://pub.dartlang.org" 582 | source: hosted 583 | version: "2.1.0" 584 | string_scanner: 585 | dependency: transitive 586 | description: 587 | name: string_scanner 588 | url: "https://pub.dartlang.org" 589 | source: hosted 590 | version: "1.1.0" 591 | synchronized: 592 | dependency: transitive 593 | description: 594 | name: synchronized 595 | url: "https://pub.dartlang.org" 596 | source: hosted 597 | version: "3.0.0" 598 | term_glyph: 599 | dependency: transitive 600 | description: 601 | name: term_glyph 602 | url: "https://pub.dartlang.org" 603 | source: hosted 604 | version: "1.2.0" 605 | test_api: 606 | dependency: transitive 607 | description: 608 | name: test_api 609 | url: "https://pub.dartlang.org" 610 | source: hosted 611 | version: "0.4.8" 612 | timeago: 613 | dependency: "direct main" 614 | description: 615 | name: timeago 616 | url: "https://pub.dartlang.org" 617 | source: hosted 618 | version: "3.1.0" 619 | timezone: 620 | dependency: transitive 621 | description: 622 | name: timezone 623 | url: "https://pub.dartlang.org" 624 | source: hosted 625 | version: "0.8.0" 626 | typed_data: 627 | dependency: transitive 628 | description: 629 | name: typed_data 630 | url: "https://pub.dartlang.org" 631 | source: hosted 632 | version: "1.3.0" 633 | uuid: 634 | dependency: transitive 635 | description: 636 | name: uuid 637 | url: "https://pub.dartlang.org" 638 | source: hosted 639 | version: "3.0.5" 640 | vector_math: 641 | dependency: transitive 642 | description: 643 | name: vector_math 644 | url: "https://pub.dartlang.org" 645 | source: hosted 646 | version: "2.1.1" 647 | webview_flutter: 648 | dependency: "direct main" 649 | description: 650 | name: webview_flutter 651 | url: "https://pub.dartlang.org" 652 | source: hosted 653 | version: "3.0.0" 654 | webview_flutter_android: 655 | dependency: transitive 656 | description: 657 | name: webview_flutter_android 658 | url: "https://pub.dartlang.org" 659 | source: hosted 660 | version: "2.8.2" 661 | webview_flutter_platform_interface: 662 | dependency: transitive 663 | description: 664 | name: webview_flutter_platform_interface 665 | url: "https://pub.dartlang.org" 666 | source: hosted 667 | version: "1.8.1" 668 | webview_flutter_wkwebview: 669 | dependency: transitive 670 | description: 671 | name: webview_flutter_wkwebview 672 | url: "https://pub.dartlang.org" 673 | source: hosted 674 | version: "2.7.1" 675 | win32: 676 | dependency: transitive 677 | description: 678 | name: win32 679 | url: "https://pub.dartlang.org" 680 | source: hosted 681 | version: "2.3.8" 682 | xdg_directories: 683 | dependency: transitive 684 | description: 685 | name: xdg_directories 686 | url: "https://pub.dartlang.org" 687 | source: hosted 688 | version: "0.2.0" 689 | xml: 690 | dependency: transitive 691 | description: 692 | name: xml 693 | url: "https://pub.dartlang.org" 694 | source: hosted 695 | version: "5.3.1" 696 | sdks: 697 | dart: ">=2.15.0 <3.0.0" 698 | flutter: ">=2.5.0" 699 | --------------------------------------------------------------------------------