├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── auto-merge.yml │ ├── autoupdate.yml │ ├── build-flutter.yml │ ├── issue-assign.yml │ └── pr_remiders.yml ├── .gitignore ├── .metadata ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── io │ │ │ │ └── flutter │ │ │ │ └── app │ │ │ │ └── FlutterMultiDexApplication.java │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── apps │ │ │ │ └── blt │ │ │ │ ├── MainActivity.kt │ │ │ │ ├── NotificationManagerImpl.kt │ │ │ │ ├── SpamCallBlockerService.kt │ │ │ │ └── SpamNumberManager.kt │ │ └── res │ │ │ ├── drawable-v21 │ │ │ └── launch_background.xml │ │ │ ├── drawable │ │ │ ├── blt_logo.xml │ │ │ ├── bugheist_logo.xml │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets ├── GitHub.svg ├── TnC.md ├── ant.svg ├── app_icon.png ├── app_large_icon.png ├── bitcoin.svg ├── blt_logo.svg ├── blt_logo_dark.svg ├── default_profile.png ├── flea.svg ├── github │ ├── contri1.png │ ├── contri2.png │ ├── gh_screen1.png │ ├── gh_screen2.png │ ├── gh_screen3.png │ └── gh_screen4.png ├── image-not-found.png ├── input_bold.svg ├── input_heading.svg ├── input_image.svg ├── input_italic.svg ├── input_link.svg ├── input_list.svg ├── input_strikethrough.svg ├── input_task.svg ├── linkedin.svg ├── login_signup │ ├── apple.png │ ├── facebook.png │ ├── google.png │ ├── icon_email.png │ ├── icon_eye_close.png │ ├── icon_eye_open.png │ ├── icon_password.png │ ├── icon_user.png │ └── user_password.png ├── logo.png ├── logo_white.svg ├── pest_control.svg ├── privacy_policy.md ├── scorpion.svg ├── select_image.svg ├── twitter.svg ├── typing.json ├── wasp.svg └── website.svg ├── codemagic.yaml ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── l10n.yaml ├── lib ├── l10n │ ├── app_de.arb │ ├── app_en.arb │ ├── app_es.arb │ ├── app_fr.arb │ ├── app_hi.arb │ ├── app_ja.arb │ ├── app_pt.arb │ └── app_zh.arb ├── main.dart └── src │ ├── app.dart │ ├── components │ ├── appbar.dart │ ├── bug_hunt_list_tile.dart │ ├── bug_hunt_search_delegate.dart │ ├── components_import.dart │ ├── contributor_card.dart │ ├── issue_intro_card.dart │ ├── issuechip.dart │ ├── issueflag.dart │ ├── issuelike.dart │ ├── onboarding │ │ ├── components │ │ │ ├── drawer_paint.dart │ │ │ └── onboard_page.dart │ │ ├── data │ │ │ └── onboard_page_data.dart │ │ ├── models │ │ │ └── onboard_page_model.dart │ │ └── onboarding.dart │ └── searchbar.dart │ ├── constants │ ├── about_constants.dart │ ├── labels_constants.dart │ ├── monthname_constants.dart │ └── socialurls_constants.dart │ ├── global │ ├── functions.dart │ └── variables.dart │ ├── models │ ├── bug_hunt_model.dart │ ├── company_model.dart │ ├── contributors_model.dart │ ├── issue_model.dart │ ├── issuedata_model.dart │ ├── leader_model.dart │ ├── leaderdata_model.dart │ ├── post_model.dart │ ├── project_model.dart │ ├── tags_model.dart │ └── user_model.dart │ ├── pages │ ├── auth │ │ ├── forgot.dart │ │ ├── login.dart │ │ └── signup.dart │ ├── bug_hunt_desc_page.dart │ ├── chat_bot_page.dart │ ├── companies │ │ ├── company_details_and_issues.dart │ │ └── company_list_page.dart │ ├── company_details.dart │ ├── contributors_info.dart │ ├── drawer │ │ ├── about.dart │ │ ├── change_password.dart │ │ ├── company_dashboard.dart │ │ ├── drawer_imports.dart │ │ ├── legal.dart │ │ ├── prev_bug_hunts.dart │ │ ├── projects.dart │ │ ├── referral.dart │ │ ├── show_bug_hunts.dart │ │ ├── social.dart │ │ ├── sponsor_page.dart │ │ └── web_view.dart │ ├── error.dart │ ├── home │ │ ├── feed.dart │ │ ├── home.dart │ │ ├── home_imports.dart │ │ ├── issues.dart │ │ ├── leaderboard.dart │ │ ├── profile.dart │ │ ├── report_bug.dart │ │ └── start_hunt.dart │ ├── issues │ │ ├── closed_issues.dart │ │ ├── issue_detail.dart │ │ ├── issues_import.dart │ │ └── open_issues.dart │ ├── leaderboards │ │ ├── company_scoreboard.dart │ │ ├── global_leaderboard.dart │ │ ├── leaderboards_imports.dart │ │ └── monthly_leaderboard.dart │ ├── onboarding_main_page.dart │ ├── pages_import.dart │ ├── sizzle │ │ ├── sizzle_home.dart │ │ ├── sizzle_login.dart │ │ ├── sizzle_state_provider.dart │ │ └── sizzle_timer.dart │ ├── spam_call_blocker │ │ ├── blocker_home.dart │ │ └── database_helper.dart │ └── welcome.dart │ ├── providers │ ├── authstate_provider.dart │ ├── bug_hunt_provider.dart │ ├── companies │ │ └── company_list_provider.dart │ ├── dark_mode_provider.dart │ ├── issuelist_provider.dart │ ├── language_provider.dart │ ├── leaderboards │ │ ├── companyscoreboard_provider.dart │ │ ├── globalleaderboard_povider.dart │ │ └── monthlyleaderboard_provider.dart │ ├── login_provider.dart │ ├── projects_provider.dart │ └── providers_imports.dart │ ├── routes │ ├── routes_import.dart │ └── routing.dart │ └── util │ ├── api │ ├── auth_api.dart │ ├── bug_hunt_api.dart │ ├── chatbot_api.dart │ ├── company_api.dart │ ├── general_api.dart │ ├── github_apis.dart │ ├── issues_api.dart │ ├── leaderboard_api.dart │ ├── project_apis.dart │ ├── tags_api.dart │ └── user_api.dart │ ├── endpoints │ ├── auth_endpoints.dart │ ├── company_endpoints.dart │ ├── general_endpoints.dart │ ├── issue_endpoints.dart │ ├── leaderboard_endpoints.dart │ └── user_endpoints.dart │ ├── enums │ ├── authstate_type.dart │ └── login_type.dart │ ├── services │ ├── init_service.dart │ ├── permission_handlers.dart │ └── shared_preferences.dart │ ├── theme_data.dart │ ├── util_import.dart │ └── validators.dart ├── linux ├── .gitignore ├── CMakeLists.txt ├── flutter │ ├── CMakeLists.txt │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake ├── main.cc ├── my_application.cc └── my_application.h ├── macos ├── .gitignore ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Podfile ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── app_icon_1024.png │ │ │ ├── app_icon_128.png │ │ │ ├── app_icon_16.png │ │ │ ├── app_icon_256.png │ │ │ ├── app_icon_32.png │ │ │ ├── app_icon_512.png │ │ │ └── app_icon_64.png │ ├── Base.lproj │ │ └── MainMenu.xib │ ├── Configs │ │ ├── AppInfo.xcconfig │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── Warnings.xcconfig │ ├── DebugProfile.entitlements │ ├── Info.plist │ ├── MainFlutterWindow.swift │ └── Release.entitlements └── RunnerTests │ └── RunnerTests.swift ├── pubspec.yaml ├── setup.sh ├── test ├── integration_tests │ ├── issue_card_test.dart │ ├── show_company_test.dart │ └── show_issues_test.dart ├── test_imports.dart └── unit_tests │ ├── bug_hunt_test.dart │ ├── company_test.dart │ ├── issue_test.dart │ ├── leaderboard_test.dart │ ├── project_test.dart │ └── user_test.dart └── windows ├── .gitignore ├── CMakeLists.txt ├── flutter ├── CMakeLists.txt ├── generated_plugin_registrant.cc ├── generated_plugin_registrant.h └── generated_plugins.cmake └── runner ├── CMakeLists.txt ├── Runner.rc ├── flutter_window.cpp ├── flutter_window.h ├── main.cpp ├── resource.h ├── resources └── app_icon.ico ├── runner.exe.manifest ├── utils.cpp ├── utils.h ├── win32_window.cpp └── win32_window.h /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM dart 2 | 3 | RUN apt-get update 4 | RUN apt-get install -y curl git unzip xz-utils zip libglu1-mesa 5 | 6 | RUN apt-get clean 7 | 8 | RUN git clone https://github.com/flutter/flutter.git -b stable --depth 1 /flutter 9 | ENV PATH="/flutter/bin:$PATH" 10 | RUN flutter doctor 11 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": { 3 | "dockerfile": "Dockerfile" 4 | }, 5 | "forwardPorts": [3000], 6 | "name": "Flutter", 7 | "customizations": { 8 | "vscode": { 9 | "extensions": [ 10 | "Dart-Code.dart-code", 11 | "Dart-Code.flutter" 12 | ] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | custom: ['https://owasp.org/donate?reponame=www-project-bug-logging-tool&title=OWASP+Bug+logging+tool',] 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | enable-beta-ecosystems: true 3 | updates: 4 | - package-ecosystem: "pub" 5 | directory: "/" 6 | schedule: 7 | interval: "daily" 8 | -------------------------------------------------------------------------------- /.github/workflows/auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: auto-merge 2 | 3 | on: 4 | pull_request: 5 | 6 | jobs: 7 | auto-merge: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: ahmadnassri/action-dependabot-auto-merge@v2 12 | with: 13 | github-token: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/autoupdate.yml: -------------------------------------------------------------------------------- 1 | name: autoupdate 2 | on: 3 | # This will trigger on all pushes to all branches. 4 | push: {} 5 | # Alternatively, you can only trigger if commits are pushed to certain branches, e.g.: 6 | # push: 7 | # branches: 8 | # - master 9 | # - unstable 10 | jobs: 11 | autoupdate: 12 | name: autoupdate 13 | runs-on: ubuntu-20.04 14 | steps: 15 | - uses: docker://chinthakagodawita/autoupdate-action:v1 16 | env: 17 | GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' -------------------------------------------------------------------------------- /.github/workflows/issue-assign.yml: -------------------------------------------------------------------------------- 1 | name: Auto Assign 2 | 3 | on: 4 | issue_comment: 5 | types: [created] 6 | schedule: 7 | - cron: '0 0 * * *' 8 | workflow_dispatch: 9 | 10 | jobs: 11 | auto-assign: 12 | runs-on: ubuntu-latest 13 | permissions: 14 | issues: write 15 | steps: 16 | - name: Assign Issues 17 | uses: OWASP-BLT/BLT-Action@main 18 | with: 19 | repo-token: ${{ secrets.GITHUB_TOKEN }} 20 | -------------------------------------------------------------------------------- /.github/workflows/pr_remiders.yml: -------------------------------------------------------------------------------- 1 | name: PRs reviews reminder 2 | 3 | on: 4 | schedule: 5 | # Runs every hour, between 14:00 and 21:00, Monday through Friday. 6 | - cron: "0,30 14-21 * * 1-5" 7 | 8 | 9 | jobs: 10 | pr-reviews-reminder: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: davideviolante/pr-reviews-reminder-action@v2.7.0 14 | env: 15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 16 | with: 17 | webhook-url: ${{ secrets.SLACK_PR_REMINDER_WEBHOOK_URL }} 18 | provider: 'slack' # Required (slack, rocket or msteams) 19 | channel: '#project-blt-prs' # Optional, eg: #general -------------------------------------------------------------------------------- /.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 | # Flutter/Dart/Pub related 19 | **/doc/api/ 20 | **/ios/Flutter/.last_build_id 21 | .dart_tool/ 22 | .flutter-plugins 23 | .flutter-plugins-dependencies 24 | .packages 25 | .pub-cache/ 26 | .pub/ 27 | /build/ 28 | *.lock 29 | 30 | # Web related 31 | lib/generated_plugin_registrant.dart 32 | 33 | # Symbolication related 34 | app.*.symbols 35 | 36 | # Obfuscation related 37 | app.*.map.json 38 | 39 | # Android Studio will place build artifacts here 40 | /android/app/debug 41 | /android/app/profile 42 | /android/app/release 43 | -------------------------------------------------------------------------------- /.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. 5 | 6 | version: 7 | revision: 9944297138845a94256f1cf37beb88ff9a8e811a 8 | channel: stable 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a 17 | base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a 18 | - platform: android 19 | create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a 20 | base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a 21 | - platform: ios 22 | create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a 23 | base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a 24 | - platform: web 25 | create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a 26 | base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a 27 | 28 | # User provided section 29 | 30 | # List of Local paths (relative to this file) that should be 31 | # ignored by the migrate tool. 32 | # 33 | # Files that are not part of the templates will be ignored by default. 34 | unmanaged_files: 35 | - 'lib/main.dart' 36 | - 'ios/Runner.xcodeproj/project.pbxproj' 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023, OWASP BLT TEAM 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /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 | 11 | #include: package:flutter_lints/flutter.yaml 12 | # has 300 errors so needs time to cleanup 13 | 14 | linter: 15 | # The lint rules applied to this project can be customized in the 16 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 17 | # included above or to enable additional rules. A list of all available lints 18 | # and their documentation is published at 19 | # https://dart-lang.github.io/linter/lints/index.html. 20 | # 21 | # Instead of disabling a lint rule for the entire project in the 22 | # section below, it can also be suppressed for a single line of code 23 | # or a specific dart file by using the `// ignore: name_of_lint` and 24 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 25 | # producing the lint. 26 | rules: 27 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 28 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 29 | 30 | # Additional information about this file can be found at 31 | # https://dart.dev/guides/language/analysis-options 32 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | 20 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 21 | if (flutterVersionName == null) { 22 | flutterVersionName = '1.0' 23 | } 24 | 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 34 31 | 32 | sourceSets { 33 | main.java.srcDirs += 'src/main/kotlin' 34 | } 35 | 36 | defaultConfig { 37 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 38 | applicationId "com.apps.blt" 39 | minSdkVersion 21 40 | targetSdkVersion 34 41 | multiDexEnabled true 42 | versionCode flutterVersionCode.toInteger() 43 | versionName flutterVersionName 44 | vectorDrawables.useSupportLibrary = true 45 | } 46 | 47 | buildTypes { 48 | release { 49 | // TODO: Add your own signing config for the release build. 50 | // Signing with the debug keys for now, so `flutter run --release` works. 51 | signingConfig signingConfigs.debug 52 | } 53 | } 54 | 55 | lintOptions { 56 | disable 'InvalidPackage' 57 | disable "Instantiatable" 58 | checkReleaseBuilds false 59 | abortOnError false 60 | } 61 | } 62 | 63 | flutter { 64 | source '../..' 65 | } 66 | 67 | dependencies { 68 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 69 | implementation "androidx.multidex:multidex:2.0.1" 70 | 71 | implementation 'androidx.core:core-ktx:1.10.1' 72 | implementation 'androidx.appcompat:appcompat:1.6.1' 73 | implementation 'androidx.activity:activity-ktx:1.7.2' 74 | implementation 'org.greenrobot:eventbus:3.2.0' 75 | implementation 'com.jakewharton.timber:timber:4.7.1' 76 | implementation 'pub.devrel:easypermissions:3.0.0' 77 | } 78 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java: -------------------------------------------------------------------------------- 1 | // Generated file. 2 | // 3 | // If you wish to remove Flutter's multidex support, delete this entire file. 4 | // 5 | // Modifications to this file should be done in a copy under a different name 6 | // as this file may be regenerated. 7 | 8 | package io.flutter.app; 9 | 10 | import android.app.Application; 11 | import android.content.Context; 12 | import androidx.annotation.CallSuper; 13 | import androidx.multidex.MultiDex; 14 | 15 | /** 16 | * Extension of {@link android.app.Application}, adding multidex support. 17 | */ 18 | public class FlutterMultiDexApplication extends Application { 19 | @Override 20 | @CallSuper 21 | protected void attachBaseContext(Context base) { 22 | super.attachBaseContext(base); 23 | MultiDex.install(this); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/apps/blt/NotificationManagerImpl.kt: -------------------------------------------------------------------------------- 1 | package com.apps.blt 2 | 3 | import android.content.Context 4 | import android.os.Looper 5 | import android.widget.Toast 6 | interface NotificationManager { 7 | fun showToastNotification(context: Context, message: String) 8 | } 9 | 10 | class NotificationManagerImpl : NotificationManager { 11 | override fun showToastNotification(context: Context, message: String) { 12 | val t = Thread { 13 | try { 14 | Looper.prepare() 15 | Toast.makeText(context.applicationContext, message, Toast.LENGTH_LONG).show() 16 | Looper.loop() 17 | } catch (e: Exception) { 18 | e.printStackTrace() 19 | } 20 | } 21 | t.start() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/apps/blt/SpamCallBlockerService.kt: -------------------------------------------------------------------------------- 1 | package com.apps.blt 2 | 3 | import android.telecom.CallScreeningService 4 | import android.telecom.Call 5 | import android.util.Log 6 | import org.greenrobot.eventbus.EventBus 7 | import java.text.SimpleDateFormat 8 | import java.util.Date 9 | import java.util.Locale 10 | import android.net.Uri 11 | 12 | class MessageEvent(val message: String) {} 13 | 14 | class SpamCallBlockerService : CallScreeningService() { 15 | private val notificationManager = NotificationManagerImpl() 16 | 17 | override fun onCreate() { 18 | super.onCreate() 19 | Log.d("SpamCallBlockerService", "Service started") 20 | } 21 | 22 | override fun onScreenCall(callDetails: Call.Details) { 23 | Log.d("SpamCallBlockerService", "onScreenCall triggered") 24 | val phoneNumber = getPhoneNumber(callDetails) 25 | Log.d("SpamCallBlockerService", "Intercepted call from: $phoneNumber") 26 | var response = CallResponse.Builder() 27 | response = handlePhoneCall(response, phoneNumber) 28 | 29 | respondToCall(callDetails, response.build()) 30 | logCallInterception(phoneNumber, response.build()) 31 | } 32 | 33 | private fun handlePhoneCall( 34 | response: CallResponse.Builder, 35 | phoneNumber: String 36 | ): CallResponse.Builder { 37 | if (SpamNumberManager.isSpamNumber(phoneNumber)) { 38 | response.apply { 39 | setRejectCall(true) 40 | setDisallowCall(true) 41 | setSkipCallLog(false) 42 | displayToast(String.format("Rejected call from %s", phoneNumber)) 43 | } 44 | } else { 45 | displayToast(String.format("Incoming call from %s", phoneNumber)) 46 | } 47 | return response 48 | } 49 | 50 | private fun getPhoneNumber(callDetails: Call.Details): String { 51 | return callDetails.handle.toString().removeTelPrefix().parseCountryCode() 52 | } 53 | 54 | private fun displayToast(message: String) { 55 | notificationManager.showToastNotification(applicationContext, message) 56 | EventBus.getDefault().post(MessageEvent(message)) 57 | } 58 | 59 | private fun logCallInterception(phoneNumber: String, response: CallResponse) { 60 | val currentTime = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date()) 61 | val action = "action" 62 | val logMessage = "[$currentTime] $action call from $phoneNumber" 63 | Log.d("SpamCallBlockerService", logMessage) 64 | } 65 | 66 | fun String.removeTelPrefix() = this.replace("tel:", "") 67 | fun String.parseCountryCode(): String = Uri.decode(this) 68 | } 69 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/apps/blt/SpamNumberManager.kt: -------------------------------------------------------------------------------- 1 | package com.apps.blt 2 | 3 | import kotlin.collections.mutableSetOf 4 | 5 | object SpamNumberManager { 6 | private val spamNumbers = mutableSetOf() 7 | 8 | fun updateSpamList(numbers: List) { 9 | spamNumbers.clear() 10 | spamNumbers.addAll(numbers) 11 | } 12 | 13 | fun isSpamNumber(number: String): Boolean { 14 | return spamNumbers.contains(number) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.7.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | 7 | } 8 | 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:7.4.2' 11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 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 | subprojects { 27 | project.evaluationDependsOn(':app') 28 | } 29 | 30 | tasks.register("clean", Delete) { 31 | delete rootProject.buildDir 32 | } 33 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Oct 29 01:30:50 IST 2024 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /assets/GitHub.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | github [#142] 6 | Created with Sketch. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /assets/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/app_icon.png -------------------------------------------------------------------------------- /assets/app_large_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/app_large_icon.png -------------------------------------------------------------------------------- /assets/bitcoin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /assets/default_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/default_profile.png -------------------------------------------------------------------------------- /assets/github/contri1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/github/contri1.png -------------------------------------------------------------------------------- /assets/github/contri2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/github/contri2.png -------------------------------------------------------------------------------- /assets/github/gh_screen1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/github/gh_screen1.png -------------------------------------------------------------------------------- /assets/github/gh_screen2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/github/gh_screen2.png -------------------------------------------------------------------------------- /assets/github/gh_screen3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/github/gh_screen3.png -------------------------------------------------------------------------------- /assets/github/gh_screen4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/github/gh_screen4.png -------------------------------------------------------------------------------- /assets/image-not-found.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/image-not-found.png -------------------------------------------------------------------------------- /assets/input_bold.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/input_heading.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/input_image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/input_italic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/input_list.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/input_strikethrough.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/input_task.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/linkedin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /assets/login_signup/apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/login_signup/apple.png -------------------------------------------------------------------------------- /assets/login_signup/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/login_signup/facebook.png -------------------------------------------------------------------------------- /assets/login_signup/google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/login_signup/google.png -------------------------------------------------------------------------------- /assets/login_signup/icon_email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/login_signup/icon_email.png -------------------------------------------------------------------------------- /assets/login_signup/icon_eye_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/login_signup/icon_eye_close.png -------------------------------------------------------------------------------- /assets/login_signup/icon_eye_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/login_signup/icon_eye_open.png -------------------------------------------------------------------------------- /assets/login_signup/icon_password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/login_signup/icon_password.png -------------------------------------------------------------------------------- /assets/login_signup/icon_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/login_signup/icon_user.png -------------------------------------------------------------------------------- /assets/login_signup/user_password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/login_signup/user_password.png -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/assets/logo.png -------------------------------------------------------------------------------- /assets/pest_control.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/privacy_policy.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy 2 | 3 | We want to make sure you, as a Customer or Finder, understand what information we collect from you and why. We also want you to know about our information use practices so that you can make good decisions about how you use BLT. 4 | 5 | This Privacy Policy explains what information we collect from and about you, (collectively, "Your Information") and what we do with it. 6 | 7 | _Please read this Privacy Policy carefully._ 8 | 9 | ## Information Collection 10 | - __Direct Collection__ 11 | - When you create an account with BLT, you are required to provide us with profile information, including your name, company name (if applicable), username, password, and email address. BLT stores this information to help identify you when you log in. 12 | 13 | - __Indirect Collection__ 14 | - We receive some information automatically when you visit BLT. This includes information about the device, browser, and operating system you use when accessing our site and Services and your IP address. If you visit BLT when you are logged into your account, we also collect the user identification number we assign you when you open your account. 15 | 16 | - __Cookie Policy__ 17 | - When you log in to your account, BLT will place cookie(s) for the purpose of creating the session, knowing when you're logged in, and recognizing you as the same authenticated user across accounts. These cookie(s) contain an encrypted user identifier. 18 | -------------------------------------------------------------------------------- /assets/select_image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /assets/twitter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/website.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /codemagic.yaml: -------------------------------------------------------------------------------- 1 | workflows: 2 | ios-workflow: 3 | triggering: 4 | events: 5 | - push 6 | cancel_previous_builds: true 7 | name: iOS Workflow 8 | max_build_duration: 120 9 | integrations: 10 | app_store_connect: codemagic 11 | environment: 12 | # ios_signing: 13 | # distribution_type: app_store 14 | # bundle_identifier: $PRODUCT_BUNDLE_IDENTIFIER 15 | flutter: stable 16 | groups: 17 | - main 18 | scripts: 19 | - name: Run setups 20 | script: | 21 | chmod +x setup.sh 22 | ./setup.sh 23 | - name: Set up code signing settings on Xcode project 24 | script: | 25 | xcode-project use-profiles 26 | - name: Get Flutter packages 27 | script: | 28 | flutter packages pub 29 | - name: Install pods 30 | script: | 31 | find . -name "Podfile" -execdir pod install \; 32 | - name: Flutter analyze 33 | script: | 34 | flutter analyze 35 | # - name: Flutter unit tests 36 | # script: | 37 | # flutter test 38 | # ignore_failure: true 39 | - name: Flutter build ipa 40 | script: | 41 | flutter build ipa --release \ 42 | --build-number=$(($(app-store-connect get-latest-app-store-build-number "$APP_ID") + 1)) \ 43 | --export-options-plist=/Users/builder/export_options.plist 44 | artifacts: 45 | - build/ios/ipa/*.ipa 46 | - /tmp/xcodebuild_logs/*.log 47 | - flutter_drive.log 48 | publishing: 49 | app_store_connect: 50 | api_key: $APP_STORE_CONNECT_PRIVATE_KEY 51 | key_id: $APP_STORE_CONNECT_KEY_IDENTIFIER 52 | issuer_id: $APP_STORE_CONNECT_ISSUER_ID 53 | submit_to_testflight: true 54 | 55 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | 2 | # Uncomment this line to define a global platform for your project 3 | platform :ios, '12.0' 4 | 5 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 6 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 7 | 8 | project 'Runner', { 9 | 'Debug' => :debug, 10 | 'Profile' => :release, 11 | 'Release' => :release, 12 | } 13 | 14 | def flutter_root 15 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 16 | unless File.exist?(generated_xcode_build_settings_path) 17 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 18 | end 19 | 20 | File.foreach(generated_xcode_build_settings_path) do |line| 21 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 22 | return matches[1].strip if matches 23 | end 24 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 25 | end 26 | 27 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 28 | 29 | flutter_ios_podfile_setup 30 | 31 | target 'Runner' do 32 | use_frameworks! 33 | use_modular_headers! 34 | 35 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 36 | end 37 | 38 | post_install do |installer| 39 | installer.pods_project.targets.each do |target| 40 | flutter_additional_ios_build_settings(target) 41 | target.build_configurations.each do |config| 42 | config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0' 43 | config.build_settings['ENABLE_BITCODE'] = 'NO' 44 | end 45 | end 46 | 47 | ################ Awesome Notifications pod modification 1 ################### 48 | awesome_pod_file = File.expand_path(File.join('plugins', 'awesome_notifications', 'ios', 'Scripts', 'AwesomePodFile'), '.symlinks') 49 | require awesome_pod_file 50 | update_awesome_pod_build_settings(installer) 51 | ################ Awesome Notifications pod modification 1 ################### 52 | end 53 | 54 | ################ Awesome Notifications pod modification 2 ################### 55 | awesome_pod_file = File.expand_path(File.join('plugins', 'awesome_notifications', 'ios', 'Scripts', 'AwesomePodFile'), '.symlinks') 56 | require awesome_pod_file 57 | update_awesome_main_target_settings('Runner', File.dirname(File.realpath(__FILE__)), flutter_root) 58 | ################ Awesome Notifications pod modification 2 ################### 59 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import UIKit 4 | 5 | @main 6 | @objc class AppDelegate: FlutterAppDelegate { 7 | override func application( 8 | _ application: UIApplication, 9 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 10 | ) -> Bool { 11 | // Register the method channel 12 | let controller = window?.rootViewController as! FlutterViewController 13 | let clipboardImageChannel = FlutterMethodChannel(name: "com.apps.blt/channel", 14 | binaryMessenger: controller.binaryMessenger) 15 | 16 | clipboardImageChannel.setMethodCallHandler { (call: FlutterMethodCall, result: @escaping FlutterResult) in 17 | if call.method == "getClipboardImage" { 18 | self.getClipboardImage(result: result) 19 | } else { 20 | result(FlutterMethodNotImplemented) 21 | } 22 | } 23 | 24 | GeneratedPluginRegistrant.register(with: self) 25 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 26 | } 27 | 28 | private func getClipboardImage(result: FlutterResult) { 29 | // Check if the clipboard contains an image 30 | if let image = UIPasteboard.general.image { 31 | // Convert the image to PNG data 32 | if let imageData = image.pngData() { 33 | // Encode the image data to a Base64 string 34 | let base64String = imageData.base64EncodedString() 35 | result(base64String) // Send the Base64 string back to Flutter 36 | } else { 37 | result(FlutterError(code: "NO_IMAGE", message: "Could not convert image to data", details: nil)) 38 | } 39 | } else { 40 | result(FlutterError(code: "NO_IMAGE", message: "Clipboard does not contain an image", details: nil)) 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/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/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/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/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/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/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/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/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/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/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/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/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/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/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/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/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/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/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/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/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/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/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/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/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Blt 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | blt 17 | NSPhotoLibraryUsageDescription 18 | This app needs access to your photo library to upload images. 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | $(FLUTTER_BUILD_NAME) 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | $(FLUTTER_BUILD_NUMBER) 27 | LSRequiresIPhoneOS 28 | 29 | UILaunchStoryboardName 30 | LaunchScreen 31 | UIMainStoryboardFile 32 | Main 33 | ITSAppUsesNonExemptEncryption 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | UIViewControllerBasedStatusBarAppearance 49 | 50 | CFBundleURLTypes 51 | 52 | 53 | CFBundleTypeRole 54 | Editor 55 | CFBundleURLSchemes 56 | 57 | ShareMedia 58 | 59 | 60 | 61 | 62 | NSPhotoLibraryUsageDescription 63 | To upload photos, please allow permission to access your photo library. 64 | NSCameraUsageDescription 65 | To upload photos, please allow permission to access your photo library. 66 | NSMicrophoneUsageDescription 67 | To upload photos, please allow permission to access your photo library. 68 | 69 | 70 | CADisableMinimumFrameDurationOnPhone 71 | 72 | UIApplicationSupportsIndirectInputEvents 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /l10n.yaml: -------------------------------------------------------------------------------- 1 | arb-dir: lib/l10n 2 | template-arb-file: app_en.arb 3 | output-localization-file: app_localizations.dart -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | //import 'package:blt/src/util/services/init_service.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'src/app.dart'; 4 | //import 'package:flutter/services.dart'; 5 | import 'package:sentry_flutter/sentry_flutter.dart'; 6 | 7 | // Application's entry point 8 | void main() async { 9 | WidgetsFlutterBinding.ensureInitialized(); 10 | //InitService.init(); // Call the init method from the InitService class 11 | const SENTRY_DSN = "https://example-234234324.com/4504877879197696"; 12 | await SentryFlutter.init( 13 | (options) { 14 | options.dsn = SENTRY_DSN; 15 | options.tracesSampleRate = 1.0; 16 | }, 17 | appRunner: () => runApp(BLT()), 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /lib/src/app.dart: -------------------------------------------------------------------------------- 1 | //import 'dart:async'; 2 | 3 | import 'package:blt/src/pages/onboarding_main_page.dart'; 4 | import 'package:blt/src/providers/dark_mode_provider.dart'; 5 | import 'package:blt/src/providers/language_provider.dart'; 6 | import 'package:blt/src/routes/routing.dart'; 7 | import 'package:blt/src/util/theme_data.dart'; 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 10 | import 'package:flutter_localizations/flutter_localizations.dart'; 11 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 12 | //import 'package:receive_sharing_intent/receive_sharing_intent.dart'; 13 | 14 | /// ### The BLT app's root widget 15 | class BLT extends StatefulWidget { 16 | const BLT({Key? key}) : super(key: key); 17 | 18 | @override 19 | BLTState createState() => BLTState(); 20 | } 21 | 22 | class BLTState extends State { 23 | final _messengerKey = GlobalKey(); 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return ProviderScope( 28 | child: GestureDetector( 29 | onTap: () { 30 | FocusScopeNode currentScope = FocusScope.of(context); 31 | if (!currentScope.hasPrimaryFocus && currentScope.hasFocus) { 32 | FocusManager.instance.primaryFocus!.unfocus(); 33 | } 34 | }, 35 | child: Consumer( 36 | builder: (context, ref, _) { 37 | final currentLanguage = ref.watch(languageProvider); 38 | final themeMode = ref.watch(darkModeProvider); 39 | 40 | return MaterialApp( 41 | localizationsDelegates: [ 42 | AppLocalizations.delegate, 43 | GlobalMaterialLocalizations.delegate, 44 | GlobalWidgetsLocalizations.delegate, 45 | GlobalCupertinoLocalizations.delegate, 46 | ], 47 | supportedLocales: AppLocalizations.supportedLocales, 48 | locale: Locale(currentLanguage), 49 | scaffoldMessengerKey: _messengerKey, 50 | debugShowCheckedModeBanner: false, 51 | onGenerateRoute: RouteManager.generateRoute, 52 | title: 'BLT', 53 | theme: AppTheme.lightTheme, 54 | darkTheme: AppTheme.darkTheme, 55 | themeMode: 56 | themeMode.isDarkMode ? ThemeMode.dark : ThemeMode.light, 57 | home: Scaffold(body: OnboardingMainPage()), 58 | ); 59 | }, 60 | ), 61 | ), 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/src/components/appbar.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/components/components_import.dart'; 2 | 3 | /// The app's main Appbar 4 | AppBar buildAppBar({required BuildContext context}) { 5 | final isDarkMode = Theme.of(context).brightness == Brightness.dark; 6 | return AppBar( 7 | title: SvgPicture.asset( 8 | isDarkMode ? 'assets/blt_logo_dark.svg' : 'assets/blt_logo.svg', 9 | fit: BoxFit.cover, 10 | height: 30, 11 | ), 12 | actions: [ 13 | IconButton( 14 | icon: Icon( 15 | Icons.search, 16 | color: isDarkMode ? Colors.grey[350] : Colors.red, 17 | ), 18 | onPressed: () { 19 | showSearch( 20 | context: context, 21 | delegate: BLTSearchDelegate(), 22 | ); 23 | }, 24 | ), 25 | IconButton( 26 | icon: Icon( 27 | Icons.account_circle, 28 | color: isDarkMode ? Colors.grey[350] : Colors.red, 29 | ), 30 | onPressed: () { 31 | if (currentUser!.id == null) { 32 | ScaffoldMessenger.of(context).showSnackBar(SnackBar( 33 | content: const Text("No profile Found Check Your Connection"), 34 | )); 35 | return; 36 | } 37 | Navigator.of(context).pushNamed( 38 | RouteManager.profilePage, 39 | ); 40 | }, 41 | ) 42 | ], 43 | elevation: 0, 44 | backgroundColor: isDarkMode 45 | ? Color.fromRGBO(58, 21, 31, 1) 46 | : Theme.of(context).canvasColor, 47 | iconTheme: isDarkMode 48 | ? IconThemeData(color: Colors.grey[350]) 49 | : IconThemeData(color: Color(0xFFDC4654)), 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /lib/src/components/bug_hunt_search_delegate.dart: -------------------------------------------------------------------------------- 1 | import './components_import.dart'; 2 | 3 | /// The search bar of app for searching issues based on keyword. 4 | class BugHuntSearchDelegate extends SearchDelegate { 5 | @override 6 | List? buildActions(BuildContext context) { 7 | return [ 8 | IconButton( 9 | onPressed: () { 10 | query != '' ? (query = '') : Navigator.of(context).pop(); 11 | }, 12 | icon: Icon( 13 | Icons.clear, 14 | color: Color(0xFFDC4654), 15 | ), 16 | ), 17 | ]; 18 | } 19 | 20 | @override 21 | Widget? buildLeading(BuildContext context) { 22 | return IconButton( 23 | icon: Icon( 24 | Icons.arrow_back_ios_new_rounded, 25 | color: Color(0xFFDC4654), 26 | ), 27 | onPressed: () { 28 | Navigator.of(context).pop(); 29 | }, 30 | ); 31 | } 32 | 33 | @override 34 | Widget buildResults(BuildContext context) { 35 | Future _getObj = 36 | BugHuntApiClient.searchBugHunts(client: null, search: query); 37 | 38 | ScrollController _scrollController = new ScrollController(); 39 | 40 | return FutureBuilder( 41 | future: _getObj, 42 | builder: (context, snapshot) { 43 | if (snapshot.connectionState == ConnectionState.done) { 44 | if (snapshot.hasError) { 45 | return Center( 46 | child: Text( 47 | 'Something went wrong!', 48 | style: TextStyle(fontSize: 18), 49 | ), 50 | ); 51 | } else if (snapshot.hasData) { 52 | return ListView.builder( 53 | padding: EdgeInsets.symmetric(horizontal: 20), 54 | itemCount: snapshot.data.length, 55 | controller: _scrollController, 56 | itemBuilder: (context, index) { 57 | return BugHuntListTile( 58 | hunt: snapshot.data[index], 59 | ); 60 | }, 61 | ); 62 | } 63 | } 64 | return Center( 65 | child: CircularProgressIndicator(), 66 | ); 67 | }, 68 | ); 69 | } 70 | 71 | @override 72 | Widget buildSuggestions(BuildContext context) { 73 | final Size size = MediaQuery.of(context).size; 74 | return Container( 75 | width: size.width, 76 | height: size.height, 77 | child: Center( 78 | child: Text( 79 | 'Search a Bug Hunt!', 80 | style: GoogleFonts.ubuntu( 81 | textStyle: TextStyle( 82 | color: Color(0xFF737373), 83 | fontSize: 20, 84 | ), 85 | ), 86 | ), 87 | ), 88 | ); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /lib/src/components/components_import.dart: -------------------------------------------------------------------------------- 1 | export 'package:blt/src/routes/routing.dart'; 2 | export 'package:flutter_svg/flutter_svg.dart'; 3 | export 'package:blt/src/components/searchbar.dart'; 4 | export 'package:blt/src/global/variables.dart'; 5 | export 'package:cached_network_image/cached_network_image.dart'; 6 | export 'package:flutter/services.dart'; 7 | export 'package:google_fonts/google_fonts.dart'; 8 | export 'package:url_launcher/url_launcher.dart'; 9 | export '../models/issue_model.dart'; 10 | export '../components/issuelike.dart'; 11 | export 'package:flutter_riverpod/flutter_riverpod.dart'; 12 | export '../providers/login_provider.dart'; 13 | export '../util/api/issues_api.dart'; 14 | export '../util/enums/login_type.dart'; 15 | export '../models/issuedata_model.dart'; 16 | export '../components/issue_intro_card.dart'; 17 | export 'package:blt/src/pages/welcome.dart'; 18 | export 'package:blt/src/components/onboarding/models/onboard_page_model.dart'; 19 | export 'package:blt/src/components/onboarding/components/drawer_paint.dart'; 20 | export 'package:blt/src/components/onboarding/components/onboard_page.dart'; 21 | export 'package:blt/src/components/onboarding/data/onboard_page_data.dart'; 22 | export 'package:smooth_page_indicator/smooth_page_indicator.dart'; 23 | export 'package:blt/src/constants/monthname_constants.dart'; 24 | export '../models/bug_hunt_model.dart'; 25 | export 'package:flutter/material.dart'; 26 | export 'package:blt/src/util/api/bug_hunt_api.dart'; 27 | export 'package:blt/src/components/bug_hunt_list_tile.dart'; 28 | export '../util/endpoints/general_endpoints.dart'; 29 | -------------------------------------------------------------------------------- /lib/src/components/issuechip.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/components/components_import.dart'; 2 | 3 | /// Chip that shows the open/close status of an issue. 4 | class IssueStatusChip extends StatelessWidget { 5 | final Issue issue; 6 | const IssueStatusChip({ 7 | Key? key, 8 | required this.issue, 9 | }) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Chip( 14 | label: Text( 15 | (issue.isOpen) ? "Open" : "Closed", 16 | style: GoogleFonts.aBeeZee( 17 | textStyle: TextStyle( 18 | fontSize: 10, 19 | color: (issue.isOpen) ? Color(0xFFA3A3A3) : Color(0xFFDC4654), 20 | ), 21 | ), 22 | ), 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/src/components/issueflag.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/components/components_import.dart'; 2 | 3 | /// Issue flags show and toggle component. 4 | class IssueFlagButton extends ConsumerStatefulWidget { 5 | final Issue issue; 6 | final Color? color; 7 | const IssueFlagButton({ 8 | Key? key, 9 | this.color, 10 | required this.issue, 11 | }) : super(key: key); 12 | 13 | @override 14 | ConsumerState createState() => 15 | _IssueFlagButtonState(); 16 | } 17 | 18 | class _IssueFlagButtonState extends ConsumerState { 19 | late int flags; 20 | late bool flagged; 21 | 22 | Future toggleIssueFlag() async { 23 | setState(() { 24 | if (flagged) { 25 | flags = flags - 1; 26 | } else { 27 | flags = flags + 1; 28 | } 29 | flagged = !flagged; 30 | }); 31 | 32 | try { 33 | bool status = await IssueApiClient.toggleIssueLikes(widget.issue.id!); 34 | if (!status) { 35 | setState(() { 36 | flags = widget.issue.flags!; 37 | flagged = widget.issue.flagged!; 38 | }); 39 | } else { 40 | widget.issue.likes = flags; 41 | widget.issue.flagged = flagged; 42 | } 43 | } catch (e) { 44 | print(e); 45 | } 46 | } 47 | 48 | @override 49 | void initState() { 50 | super.initState(); 51 | flagged = widget.issue.flagged!; 52 | flags = widget.issue.flags!; 53 | } 54 | 55 | @override 56 | Widget build(BuildContext context) { 57 | return TextButton.icon( 58 | onPressed: () async { 59 | if (ref.read(loginProvider.notifier).loginType == LoginType.guest) { 60 | ScaffoldMessenger.of(context).showSnackBar( 61 | SnackBar( 62 | content: Text("Login to like and flag issues!"), 63 | ), 64 | ); 65 | } else { 66 | await toggleIssueFlag(); 67 | } 68 | }, 69 | icon: Icon( 70 | Icons.flag_outlined, 71 | color: widget.color, 72 | ), 73 | label: Text( 74 | "${flags}", 75 | style: TextStyle( 76 | color: widget.color, 77 | ), 78 | ), 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/src/components/issuelike.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/components/components_import.dart'; 2 | 3 | /// Issue likes show and toggle component. 4 | class IssueLikeButton extends ConsumerStatefulWidget { 5 | final Issue issue; 6 | final Color? color; 7 | 8 | const IssueLikeButton({ 9 | Key? key, 10 | required this.issue, 11 | this.color, 12 | }) : super(key: key); 13 | 14 | @override 15 | ConsumerState createState() => 16 | _IssueLikeButtonState(); 17 | } 18 | 19 | class _IssueLikeButtonState extends ConsumerState { 20 | late int likes; 21 | late bool liked; 22 | 23 | Future toggleIssueLike() async { 24 | setState(() { 25 | if (liked) { 26 | likes = likes - 1; 27 | } else { 28 | likes = likes + 1; 29 | } 30 | liked = !liked; 31 | }); 32 | 33 | try { 34 | bool status = await IssueApiClient.toggleIssueLikes(widget.issue.id!); 35 | if (!status) { 36 | setState(() { 37 | likes = widget.issue.likes!; 38 | liked = widget.issue.liked!; 39 | }); 40 | } else { 41 | widget.issue.likes = likes; 42 | widget.issue.liked = liked; 43 | } 44 | } catch (e) { 45 | print(e); 46 | } 47 | } 48 | 49 | @override 50 | void initState() { 51 | super.initState(); 52 | liked = widget.issue.liked!; 53 | likes = widget.issue.likes!; 54 | } 55 | 56 | @override 57 | Widget build(BuildContext context) { 58 | return TextButton.icon( 59 | onPressed: () async { 60 | if (ref.read(loginProvider.notifier).loginType == LoginType.guest) { 61 | ScaffoldMessenger.of(context).showSnackBar( 62 | SnackBar( 63 | content: Text("Login to like and flag issues!"), 64 | ), 65 | ); 66 | } else { 67 | await toggleIssueLike(); 68 | } 69 | }, 70 | icon: Icon( 71 | (liked) ? Icons.favorite : Icons.favorite_border_rounded, 72 | color: widget.color, 73 | ), 74 | label: Text( 75 | "$likes", 76 | style: TextStyle( 77 | color: widget.color, 78 | ), 79 | ), 80 | ); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /lib/src/components/onboarding/components/drawer_paint.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DrawerPaint extends CustomPainter { 4 | final Color curveColor; 5 | final Paint curvePaint; 6 | 7 | DrawerPaint({ 8 | this.curveColor = Colors.pink, 9 | }) : curvePaint = Paint() 10 | ..color = curveColor 11 | ..style = PaintingStyle.fill; 12 | 13 | @override 14 | void paint(Canvas canvas, Size size) { 15 | var path = Path(); 16 | var diameter = size.height / 3; 17 | 18 | path.moveTo(35, 0); 19 | path.relativeCubicTo(25, diameter * 0.4, -15, diameter / 2, 0, diameter); 20 | path.relativeCubicTo(30, diameter * 0.6, -15, diameter / 2, 0, diameter); 21 | path.relativeCubicTo(35, diameter * 0.7, -80, diameter * 0.7, 0, diameter); 22 | 23 | path.lineTo(size.width, size.height); 24 | path.lineTo(size.width, 0); 25 | path.close(); 26 | 27 | canvas.drawPath(path, curvePaint); 28 | } 29 | 30 | @override 31 | bool shouldRepaint(CustomPainter oldDelegate) { 32 | return true; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/src/components/onboarding/data/onboard_page_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/components/components_import.dart'; 2 | 3 | List onboardData = [ 4 | OnboardPageModel( 5 | Color(0xFFDC4654), 6 | Colors.white, 7 | Color(0xFFFFE074), 8 | 0, 9 | 'assets/logo_white.svg', 10 | 'INSIGHT', 11 | 'BLT', 12 | 'BLT is a bug-hunting & logging tool which allows you, the user or company to hunt for bugs, claim bug hounties and allow you to start bughunting spree/contest respectively.', 13 | ), 14 | OnboardPageModel( 15 | Colors.white, 16 | Color(0xFFDC4654), 17 | Color(0xFFE6E6E6), 18 | 1, 19 | 'assets/blt_logo.svg', 20 | 'EARN', 21 | 'POINTS', 22 | '(+1) Invite friends\n(+2) Verify other bug reports\n(+3) Fix issues on websites, apps or hardware\n(+4) Find a bug on a new site or app', 23 | ), 24 | OnboardPageModel( 25 | Color(0xFFDC4654), 26 | Colors.white, 27 | Color(0xFFE6E6E6), 28 | 2, 29 | 'assets/logo_white.svg', 30 | 'CURRENT', 31 | 'STATISTICS', 32 | '1200+ Bugs\n790+ Users\n3 Hunts\n590+ Domains', 33 | ), 34 | ]; 35 | -------------------------------------------------------------------------------- /lib/src/components/onboarding/models/onboard_page_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | class OnboardPageModel { 4 | final Color primeColor; 5 | final Color accentColor; 6 | final Color nextAccentColor; 7 | final int pageNumber; 8 | final String imagePath; 9 | final String caption; 10 | final String subhead; 11 | String description; 12 | 13 | OnboardPageModel( 14 | this.primeColor, 15 | this.accentColor, 16 | this.nextAccentColor, 17 | this.pageNumber, 18 | this.imagePath, 19 | this.caption, 20 | this.subhead, 21 | this.description); 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/components/searchbar.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/components/components_import.dart'; 2 | 3 | /// The search bar of app for searching issues based on keyword. 4 | class BLTSearchDelegate extends SearchDelegate { 5 | @override 6 | List? buildActions(BuildContext context) { 7 | return [ 8 | IconButton( 9 | onPressed: () { 10 | query != '' ? (query = '') : Navigator.of(context).pop(); 11 | }, 12 | icon: Icon( 13 | Icons.clear, 14 | color: Color(0xFFDC4654), 15 | ), 16 | ), 17 | ]; 18 | } 19 | 20 | @override 21 | Widget? buildLeading(BuildContext context) { 22 | return IconButton( 23 | icon: Icon( 24 | Icons.arrow_back_ios_new_rounded, 25 | color: Color(0xFFDC4654), 26 | ), 27 | onPressed: () { 28 | Navigator.of(context).pop(); 29 | }, 30 | ); 31 | } 32 | 33 | @override 34 | Widget buildResults(BuildContext context) { 35 | Future _getObj = IssueApiClient.searchIssueByKeyWord(query); 36 | 37 | ScrollController _scrollController = new ScrollController(); 38 | 39 | return FutureBuilder( 40 | future: _getObj, 41 | builder: (context, snapshot) { 42 | if (snapshot.connectionState == ConnectionState.done) { 43 | if (snapshot.hasError) { 44 | return Center( 45 | child: Text( 46 | 'Something went wrong!', 47 | style: TextStyle(fontSize: 18), 48 | ), 49 | ); 50 | } else if (snapshot.hasData) { 51 | return ListView.builder( 52 | padding: EdgeInsets.symmetric(horizontal: 20), 53 | itemCount: (snapshot.data! as IssueData).issueList!.length, 54 | controller: _scrollController, 55 | itemBuilder: (context, index) { 56 | return IssueCard( 57 | issue: (snapshot.data! as IssueData).issueList![index], 58 | ); 59 | }, 60 | ); 61 | } 62 | } 63 | return Center( 64 | child: CircularProgressIndicator(), 65 | ); 66 | }, 67 | ); 68 | } 69 | 70 | @override 71 | Widget buildSuggestions(BuildContext context) { 72 | final Size size = MediaQuery.of(context).size; 73 | return Container( 74 | width: size.width, 75 | height: size.height, 76 | child: Center( 77 | child: Text( 78 | 'Search an issue!', 79 | style: GoogleFonts.ubuntu( 80 | textStyle: TextStyle( 81 | color: Color(0xFF737373), 82 | fontSize: 20, 83 | ), 84 | ), 85 | ), 86 | ), 87 | ); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /lib/src/constants/about_constants.dart: -------------------------------------------------------------------------------- 1 | // Constants for the About Page 2 | 3 | final String aboutBLT = 4 | """Software code allows us to buy a gift for Mom or Dad on amazon.com in 7 seconds, watch our favorite “House of Cards” episode on Netflix or read Yelp reviews about a new restaurant.\n 5 | When we can’t access the information we’re looking for on the internet within seconds, we are not happy. 6 | \nThis is where you come into the picture. 7 | \nBLT wants you to identify the software (and hardware) bugs that delay downloads, freeze screens, create payloads that deliver malware to websites and generate other issues."""; 8 | 9 | final String forYou = '''\u2022 Points. 10 | \u2022 Money if you join a BLT Sponsored Bug Hunt. 11 | \u2022 Jackpot money listed on the Leaderboard. 12 | \u2022 Money if someone tips you for finding a bug through the tip button. 13 | \u2022 Experience to add to your résumé or portfolio.'''; 14 | 15 | final String forTesters = '''1. Create a User Account to log into BLT. 16 | 2. Describe the software or hardware bug you found. 17 | 3. Attach a screenshot of the bug. 18 | 4. Submit the information. 19 | 5. Win money through company-sponsored Bug Hunts, tips or the Grand Prize/Jackpot.We may also have 'heists' where each bug is worth a specific amount based on what the company sets. 20 | 6. If you participate in BLT’s sponsored Bug Hunts, you could win prize money known as tips.'''; 21 | 22 | final String forOrgs = ''' 23 | We want everyone to love your website and apps.\n 24 | You want to keep your customers happy by giving them a consistent bug-free user experience. 25 | BLT offers the ability to start a bug hunt and have testers from around the world test your site. 26 | '''; 27 | -------------------------------------------------------------------------------- /lib/src/constants/labels_constants.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | final Map labels = { 4 | 0: "General", 5 | 1: "Number error", 6 | 2: "Functional", 7 | 3: "Performance", 8 | 4: "Security", 9 | 5: "Type", 10 | 6: "Design", 11 | 7: "Server down", 12 | }; 13 | 14 | // final Map labelColors = { 15 | // 0: Colors.blue.shade700, 16 | // 1: Colors.orange.shade600, 17 | // 2: Colors.purple.shade600, 18 | // 3: Colors.yellow.shade800, 19 | // 4: Colors.indigo.shade600, 20 | // 5: Colors.teal.shade700, 21 | // 6: Colors.brown.shade600, 22 | // 7: Colors.grey.shade600, 23 | // }; 24 | 25 | Color getLabelColor(int index) { 26 | switch (index) { 27 | case 0: 28 | return Colors.blue.shade700; 29 | case 1: 30 | return Colors.orange.shade600; 31 | case 2: 32 | return Colors.purple.shade600; 33 | case 3: 34 | return Colors.yellow.shade800; 35 | case 4: 36 | return Colors.indigo.shade600; 37 | case 5: 38 | return Colors.teal.shade700; 39 | case 6: 40 | return Colors.brown.shade600; 41 | case 7: 42 | return Colors.grey.shade600; 43 | default: 44 | return Colors.white; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/src/constants/monthname_constants.dart: -------------------------------------------------------------------------------- 1 | final Map monthsInYear = { 2 | 1: "January", 3 | 2: "February", 4 | 3: "March", 5 | 4: "April", 6 | 5: "May", 7 | 6: "June", 8 | 7: "July", 9 | 8: "August", 10 | 9: "September", 11 | 10: "October", 12 | 11: "November", 13 | 12: "December" 14 | }; 15 | -------------------------------------------------------------------------------- /lib/src/constants/socialurls_constants.dart: -------------------------------------------------------------------------------- 1 | Map socialUrls = { 2 | "twitter": "https://twitter.com/owasp", 3 | "slack": "https://owasp.org/slack/invite", 4 | "github": "https://github.com/OWASP/BLT", 5 | "sponsor": 6 | "https://owasp.org/donate/?reponame=www-project-bug-logging-tool&title=OWASP+Bug+Logging+Tool", 7 | }; 8 | -------------------------------------------------------------------------------- /lib/src/global/functions.dart: -------------------------------------------------------------------------------- 1 | // Global functions that work throughout the app. -------------------------------------------------------------------------------- /lib/src/global/variables.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/models/user_model.dart'; 2 | 3 | // Global variables used throughout the app. 4 | 5 | /// The user that is currently using the app. 6 | User? currentUser; 7 | -------------------------------------------------------------------------------- /lib/src/models/bug_hunt_model.dart: -------------------------------------------------------------------------------- 1 | class BugHunt { 2 | final int id; 3 | final String name; 4 | final String url; 5 | String? logo; 6 | String? banner; 7 | String? description; 8 | final int prize; 9 | DateTime? startsOn; 10 | DateTime? endsOn; 11 | BugHunt({ 12 | required this.id, 13 | required this.name, 14 | required this.url, 15 | this.logo, 16 | this.banner, 17 | this.description, 18 | required this.prize, 19 | this.startsOn, 20 | this.endsOn, 21 | }); 22 | 23 | BugHunt copyWith({ 24 | int? id, 25 | String? name, 26 | String? url, 27 | String? logo, 28 | String? banner, 29 | String? description, 30 | int? prize, 31 | DateTime? startsOn, 32 | DateTime? endsOn, 33 | }) { 34 | return BugHunt( 35 | id: id ?? this.id, 36 | name: name ?? this.name, 37 | url: url ?? this.url, 38 | logo: logo ?? this.logo, 39 | banner: banner ?? this.banner, 40 | description: description ?? this.description, 41 | prize: prize ?? this.prize, 42 | startsOn: startsOn ?? this.startsOn, 43 | endsOn: endsOn ?? this.endsOn, 44 | ); 45 | } 46 | 47 | factory BugHunt.fromJson(dynamic json) { 48 | return BugHunt( 49 | id: json["id"], 50 | name: json["name"] ?? "", 51 | url: json["url"] ?? "", 52 | logo: json["logo"] ?? "", 53 | banner: json["banner"] ?? "", 54 | description: json["description"] ?? "", 55 | prize: json["prize"], 56 | startsOn: (json["starts_on"] != null) 57 | ? DateTime.parse(json["starts_on"]) 58 | : null, 59 | endsOn: (json["end_on"] != null) 60 | ? DateTime.parse(json["end_on"] ?? "") 61 | : null, 62 | ); 63 | } 64 | 65 | static List fromSnapshot(List json) { 66 | return json.map((data) => BugHunt.fromJson(data)).toList(); 67 | } 68 | 69 | @override 70 | String toString() { 71 | return 'BugHunt(id: $id, name: $name, url: $url, logo: $logo,banner:$banner,description:$description, prize: $prize, startsOn: $startsOn, endsOn: $endsOn)'; 72 | } 73 | 74 | @override 75 | bool operator ==(covariant BugHunt other) { 76 | if (identical(this, other)) return true; 77 | 78 | return other.id == id && 79 | other.name == name && 80 | other.url == url && 81 | other.logo == logo && 82 | other.banner == banner && 83 | other.description == description && 84 | other.prize == prize && 85 | other.startsOn == startsOn && 86 | other.endsOn == endsOn; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /lib/src/models/company_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | /// Model class for a company/domain on BLT 4 | class Company { 5 | int? id; 6 | final String companyName; 7 | String? description; 8 | String? email; 9 | String? url; 10 | String? hexcolor; 11 | String? twitter; 12 | String? facebook; 13 | int? openIssues; 14 | int? closedIssues; 15 | int? issueCount; 16 | final DateTime lastModified; 17 | final String logoLink; 18 | final String topTester; 19 | bool? isActive; 20 | 21 | Company( 22 | this.id, 23 | this.companyName, 24 | this.description, 25 | this.email, 26 | this.url, 27 | this.hexcolor, 28 | this.openIssues, 29 | this.closedIssues, 30 | this.issueCount, 31 | this.lastModified, 32 | this.logoLink, 33 | this.topTester, 34 | this.twitter, 35 | this.facebook, 36 | this.isActive, 37 | ); 38 | 39 | Color? get valueColor { 40 | Color? color; 41 | try { 42 | String val = "0xFF" + this.hexcolor!.toUpperCase(); 43 | int colorInt = int.parse(val); 44 | color = Color(colorInt); 45 | } catch (e) { 46 | print(e); 47 | } 48 | return color; 49 | } 50 | 51 | factory Company.fromJson(Map parsedJson) { 52 | return Company( 53 | parsedJson["id"] ?? null, 54 | parsedJson["name"], 55 | parsedJson["description"] ?? null, 56 | parsedJson["email"] ?? null, 57 | parsedJson["url"] ?? null, 58 | parsedJson["color"] ?? null, 59 | parsedJson["open"] ?? 0, 60 | parsedJson["closed"] ?? 0, 61 | parsedJson["issue_count"] ?? 0, 62 | DateTime.parse(parsedJson["modified"]), 63 | parsedJson["logo"] ?? "", 64 | parsedJson["top"] ?? "", 65 | parsedJson["twitter"], 66 | parsedJson["facebook"], 67 | parsedJson["isActive"], 68 | ); 69 | } 70 | 71 | static List fromSnapshot(List json) { 72 | return json.map((data) => Company.fromJson(data)).toList(); 73 | } 74 | 75 | void setMoreInfo( 76 | int id, 77 | String mail, 78 | String link, 79 | String color, 80 | ) { 81 | this.id = id; 82 | this.email = mail; 83 | this.url = link; 84 | this.hexcolor = color.substring(1); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lib/src/models/contributors_model.dart: -------------------------------------------------------------------------------- 1 | class Contributors { 2 | final int id; 3 | final String name; 4 | final int githubId; 5 | final String githubUrl; 6 | final String image; 7 | final String type; 8 | final int contributions; 9 | 10 | Contributors({ 11 | required this.id, 12 | required this.name, 13 | required this.githubId, 14 | required this.githubUrl, 15 | required this.image, 16 | required this.type, 17 | required this.contributions, 18 | }); 19 | 20 | Contributors copyWith({ 21 | int? id, 22 | String? name, 23 | int? githubId, 24 | String? githubUrl, 25 | String? image, 26 | String? type, 27 | int? contributions, 28 | }) { 29 | return Contributors( 30 | id: id ?? this.id, 31 | name: name ?? this.name, 32 | githubId: id ?? this.githubId, 33 | githubUrl: githubUrl ?? this.githubUrl, 34 | image: image ?? this.image, 35 | type: type ?? this.type, 36 | contributions: contributions ?? this.contributions, 37 | ); 38 | } 39 | 40 | factory Contributors.fromJson(dynamic json) { 41 | return Contributors( 42 | id: json['id'], 43 | name: json['name'], 44 | githubId: json['github_id'], 45 | githubUrl: json['github_url'], 46 | image: json['avatar_url'], 47 | type: json['contributor_type'], 48 | contributions: json['contributions'], 49 | ); 50 | } 51 | static List fromSnapshot(List json) { 52 | return json.map((data) => Contributors.fromJson(data)).toList(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/src/models/issuedata_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/models/issue_model.dart'; 2 | 3 | /// Model class for the paginated data sent on requesting issues. 4 | class IssueData { 5 | final int count; 6 | String? nextQuery; 7 | String? previousQuery; 8 | List? issueList; 9 | 10 | IssueData({ 11 | required this.count, 12 | this.nextQuery, 13 | this.previousQuery, 14 | this.issueList, 15 | }); 16 | 17 | factory IssueData.fromJson(Map responseData) { 18 | return IssueData( 19 | count: responseData["count"], 20 | nextQuery: responseData["next"], 21 | previousQuery: responseData["previous"], 22 | issueList: responseData["results"], 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/src/models/leader_model.dart: -------------------------------------------------------------------------------- 1 | class Leaders { 2 | final String id; 3 | final int rank; 4 | final String user; 5 | final int score; 6 | final String image; 7 | final int title; 8 | 9 | Leaders({ 10 | required this.id, 11 | required this.rank, 12 | required this.user, 13 | required this.score, 14 | required this.image, 15 | required this.title, 16 | }); 17 | 18 | factory Leaders.fromJson(Map parsedJson) { 19 | return Leaders( 20 | id: parsedJson['id'].toString(), 21 | rank: parsedJson['rank'] ?? 0, 22 | user: parsedJson['User'] ?? "", 23 | score: parsedJson['score']['total_score'] ?? 0, 24 | image: parsedJson['image']['user_avatar'] ?? "", 25 | title: parsedJson['title_type']['title'] ?? 0, 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/models/leaderdata_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/models/leader_model.dart'; 2 | 3 | /// Model class for the paginated data sent on requesting issues. 4 | class LeaderData { 5 | final int count; 6 | String? nextQuery; 7 | String? previousQuery; 8 | List? leaderList; 9 | 10 | LeaderData({ 11 | required this.count, 12 | this.nextQuery, 13 | this.previousQuery, 14 | this.leaderList, 15 | }); 16 | 17 | factory LeaderData.fromJson(Map responseData) { 18 | return LeaderData( 19 | count: responseData["count"], 20 | nextQuery: responseData["next"], 21 | previousQuery: responseData["previous"], 22 | leaderList: responseData["results"], 23 | ); 24 | } 25 | } -------------------------------------------------------------------------------- /lib/src/models/post_model.dart: -------------------------------------------------------------------------------- 1 | class SocialPosts { 2 | final String author; 3 | final userHandle; 4 | final DateTime createdAt; 5 | final String description; 6 | 7 | SocialPosts(this.author, this.userHandle, this.createdAt, this.description); 8 | } 9 | -------------------------------------------------------------------------------- /lib/src/models/project_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/models/contributors_model.dart'; 2 | 3 | class Project { 4 | final int id; 5 | final String name; 6 | final String slug; 7 | final String description; 8 | final String github_url; 9 | String? wiki_url; 10 | String? homepage_url; 11 | String? logo_url; 12 | DateTime? created; 13 | List? contributors; 14 | 15 | Project({ 16 | required this.id, 17 | required this.name, 18 | required this.slug, 19 | required this.description, 20 | required this.github_url, 21 | this.wiki_url, 22 | this.homepage_url, 23 | this.logo_url, 24 | this.created, 25 | this.contributors, 26 | }); 27 | 28 | Project copyWith({ 29 | int? id, 30 | String? name, 31 | String? slug, 32 | String? description, 33 | String? github_url, 34 | String? wiki_url, 35 | String? homepage_url, 36 | String? logo_url, 37 | DateTime? created, 38 | List? contributors, 39 | }) { 40 | return Project( 41 | id: id ?? this.id, 42 | name: name ?? this.name, 43 | slug: slug ?? this.slug, 44 | description: description ?? this.description, 45 | github_url: github_url ?? this.github_url, 46 | wiki_url: wiki_url ?? this.wiki_url, 47 | homepage_url: homepage_url ?? this.homepage_url, 48 | logo_url: logo_url ?? this.logo_url, 49 | created: created ?? this.created, 50 | contributors: contributors ?? this.contributors, 51 | ); 52 | } 53 | 54 | factory Project.fromJson(dynamic json) { 55 | return Project( 56 | id: json["id"], 57 | name: json['name'], 58 | slug: json['slug'], 59 | description: json['description'], 60 | github_url: json['github_url'], 61 | wiki_url: json['wiki_url'] != null ? json['wiki_url'] as String : "", 62 | homepage_url: 63 | json['homepage_url'] != null ? json['homepage_url'] as String : "", 64 | logo_url: json['logo_url'] != null ? json['logo_url'] : "", 65 | created: json['created'] != null ? DateTime.parse(json['created']) : null, 66 | contributors: json['contributors'] != null 67 | ? Contributors.fromSnapshot(json['contributors']) 68 | : null, 69 | ); 70 | } 71 | 72 | static List fromSnapshot(List json) { 73 | return json.map((data) => Project.fromJson(data)).toList(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/src/models/tags_model.dart: -------------------------------------------------------------------------------- 1 | class Tag { 2 | final int id; 3 | final String name; 4 | Tag({ 5 | required this.id, 6 | required this.name, 7 | }); 8 | 9 | Tag copyWith({ 10 | int? id, 11 | String? name, 12 | }) { 13 | return Tag( 14 | id: id ?? this.id, 15 | name: name ?? this.name, 16 | ); 17 | } 18 | 19 | factory Tag.fromJson(dynamic json) { 20 | return Tag( 21 | id: json["id"], 22 | name: json["name"], 23 | ); 24 | } 25 | 26 | static Map toJson(Tag tag) { 27 | return { 28 | "id": tag.id, 29 | "name": tag.name, 30 | }; 31 | } 32 | 33 | static List fromSnapshot(List json) { 34 | return json.map((data) => Tag.fromJson(data)).toList(); 35 | } 36 | 37 | static List> fromListToJson(List tags) { 38 | return tags.map((tag) => Tag.toJson(tag)).toList(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/models/user_model.dart: -------------------------------------------------------------------------------- 1 | /// Model class for a user signed up on BLT. 2 | class User { 3 | int? id; 4 | String? username; 5 | String? token; 6 | String? email; 7 | String? pfpLink; 8 | int? title; 9 | String? description; 10 | String? winning; 11 | List? following; 12 | List? likedIssueId; 13 | List? savedIssueId; 14 | List? flaggedIssueId; 15 | int? totalScore; 16 | 17 | User({ 18 | this.id, 19 | this.username, 20 | this.token, 21 | this.email, 22 | this.pfpLink, 23 | this.title, 24 | this.description, 25 | this.winning, 26 | this.following, 27 | this.likedIssueId, 28 | this.savedIssueId, 29 | this.flaggedIssueId, 30 | this.totalScore, 31 | }); 32 | 33 | factory User.fromJson(Map responseData, String accessToken) { 34 | return User( 35 | id: responseData['pk'], 36 | username: responseData['username'], 37 | email: responseData['email'], 38 | token: accessToken, 39 | pfpLink: responseData["user_avatar"], 40 | description: responseData["description"], 41 | winning: responseData["winnings"], 42 | following: responseData["follows"], 43 | likedIssueId: responseData["issue_upvoted"], 44 | savedIssueId: responseData["issue_saved"], 45 | flaggedIssueId: responseData["issue_flaged"], 46 | totalScore: responseData["total_score"] ?? 0, 47 | ); 48 | } 49 | } 50 | 51 | /// The [User] instance used for anonymous login. 52 | User guestUser = User( 53 | id: 1234567890, 54 | username: "Anonymous", 55 | token: "anonymousuest@987654321", 56 | email: "anonymous@gmail.com", 57 | pfpLink: 58 | "https://secure.gravatar.com/avatar/3633ff387ed54aa6d8e9a1593192b8de.jpg?s=200&d=mm&r=g", 59 | description: "I like to stay anonymous!", 60 | following: [], 61 | likedIssueId: [], 62 | savedIssueId: [], 63 | flaggedIssueId: [], 64 | ); 65 | -------------------------------------------------------------------------------- /lib/src/pages/drawer/drawer_imports.dart: -------------------------------------------------------------------------------- 1 | export 'package:blt/src/components/contributor_card.dart'; 2 | export 'package:blt/src/constants/about_constants.dart'; 3 | export 'package:blt/src/util/api/general_api.dart'; 4 | export 'package:cached_network_image/cached_network_image.dart'; 5 | export 'package:flutter_svg/flutter_svg.dart'; 6 | export 'package:google_fonts/google_fonts.dart'; 7 | export 'package:blt/src/util/api/auth_api.dart'; 8 | export 'package:flutter_riverpod/flutter_riverpod.dart'; 9 | export 'package:flutter/services.dart'; 10 | export 'package:flutter_markdown/flutter_markdown.dart'; 11 | export 'package:font_awesome_flutter/font_awesome_flutter.dart'; 12 | export 'package:url_launcher/url_launcher.dart'; 13 | export '../../constants/socialurls_constants.dart'; 14 | export 'package:blt/src/pages/drawer/web_view.dart'; 15 | export 'package:flutter/material.dart'; 16 | export 'package:webview_flutter/webview_flutter.dart'; 17 | export 'package:flutter_gen/gen_l10n/app_localizations.dart'; 18 | export 'package:blt/src/models/bug_hunt_model.dart'; 19 | export 'package:blt/src/providers/bug_hunt_provider.dart'; 20 | export 'package:blt/src/components/bug_hunt_list_tile.dart'; 21 | export 'package:blt/src/components/bug_hunt_search_delegate.dart'; 22 | export '../../routes/routing.dart'; 23 | export 'package:blt/src/models/contributors_model.dart'; 24 | export 'package:blt/src/models/project_model.dart'; 25 | export 'package:blt/src/util/api/github_apis.dart'; 26 | -------------------------------------------------------------------------------- /lib/src/pages/home/home_imports.dart: -------------------------------------------------------------------------------- 1 | export 'package:google_fonts/google_fonts.dart'; 2 | export 'package:flutter_riverpod/flutter_riverpod.dart'; 3 | export '../../global/variables.dart'; 4 | export 'package:blt/src/pages/home/issues.dart'; 5 | export 'package:blt/src/pages/home/leaderboard.dart'; 6 | export 'package:blt/src/pages/home/report_bug.dart'; 7 | export 'package:blt/src/pages/home/start_hunt.dart'; 8 | export 'package:blt/src/providers/authstate_provider.dart'; 9 | export 'package:blt/src/providers/login_provider.dart'; 10 | export 'package:blt/src/routes/routing.dart'; 11 | export 'package:blt/src/util/enums/login_type.dart'; 12 | export 'package:cached_network_image/cached_network_image.dart'; 13 | export 'package:receive_sharing_intent/receive_sharing_intent.dart'; 14 | export '../../components/appbar.dart'; 15 | export '../../pages/welcome.dart'; 16 | export 'package:blt/src/providers/issuelist_provider.dart'; 17 | export '../../components/issue_intro_card.dart'; 18 | export '../../models/issue_model.dart'; 19 | export '../../util/endpoints/issue_endpoints.dart'; 20 | export '../../constants/monthname_constants.dart'; 21 | export '../../providers/leaderboards/globalleaderboard_povider.dart'; 22 | export '../../providers/leaderboards/monthlyleaderboard_provider.dart'; 23 | export '../../providers/leaderboards/companyscoreboard_provider.dart'; 24 | export 'package:blt/src/util/api/user_api.dart'; 25 | export 'package:image_picker/image_picker.dart'; 26 | export '../../models/user_model.dart'; 27 | export '../../util/api/issues_api.dart'; 28 | export '../../components/issuechip.dart'; 29 | export '../../models/issuedata_model.dart'; 30 | export 'dart:io'; 31 | export 'dart:math'; 32 | export 'package:blt/src/util/api/general_api.dart'; 33 | export 'package:blt/src/util/endpoints/general_endpoints.dart'; 34 | export 'package:flutter/gestures.dart'; 35 | export 'package:flutter_svg/flutter_svg.dart'; 36 | export 'package:url_launcher/url_launcher.dart'; 37 | export 'package:flutter_markdown/flutter_markdown.dart'; 38 | export 'package:pasteboard/pasteboard.dart'; 39 | export 'package:flutter_gen/gen_l10n/app_localizations.dart'; 40 | export 'package:blt/src/providers/companies/company_list_provider.dart'; 41 | export 'package:blt/src/providers/providers_imports.dart'; 42 | export 'package:flutter/material.dart'; 43 | export 'package:blt/src/providers/dark_mode_provider.dart'; 44 | -------------------------------------------------------------------------------- /lib/src/pages/issues/issues_import.dart: -------------------------------------------------------------------------------- 1 | export 'package:google_fonts/google_fonts.dart'; 2 | export 'package:flutter_markdown/flutter_markdown.dart'; 3 | export '../../models/issue_model.dart'; 4 | export '../../components/issuechip.dart'; 5 | export '../../components/issueflag.dart'; 6 | export '../../components/issuelike.dart'; 7 | export 'package:flutter_gen/gen_l10n/app_localizations.dart'; 8 | -------------------------------------------------------------------------------- /lib/src/pages/leaderboards/leaderboards_imports.dart: -------------------------------------------------------------------------------- 1 | export 'package:blt/src/util/endpoints/leaderboard_endpoints.dart'; 2 | export 'package:cached_network_image/cached_network_image.dart'; 3 | export 'package:google_fonts/google_fonts.dart'; 4 | export '../../routes/routing.dart'; 5 | export '../../util/api/company_api.dart'; 6 | export '../../util/api/leaderboard_api.dart'; 7 | export 'package:blt/src/providers/leaderboards/monthlyleaderboard_provider.dart'; 8 | export 'package:flutter_riverpod/flutter_riverpod.dart'; 9 | export '../../models/leader_model.dart'; 10 | export '../../constants/monthname_constants.dart'; 11 | export 'package:flutter_gen/gen_l10n/app_localizations.dart'; 12 | -------------------------------------------------------------------------------- /lib/src/pages/onboarding_main_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/pages/pages_import.dart'; 2 | 3 | class OnboardingMainPage extends ConsumerStatefulWidget { 4 | @override 5 | ConsumerState createState() => _OnboardingMainPageState(); 6 | } 7 | 8 | class _OnboardingMainPageState extends ConsumerState { 9 | Map stats = {}; 10 | 11 | @override 12 | void initState() { 13 | super.initState(); 14 | WidgetsBinding.instance.addPostFrameCallback((_) async { 15 | await ref.read(authStateNotifier.notifier).loadUserIfRemembered(context); 16 | Map new_stats = await GeneralApiClient.getStats(); 17 | if (!mounted) { 18 | return; 19 | } 20 | setState(() { 21 | stats = new_stats; 22 | }); 23 | }); 24 | } 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | if (stats["bugs"] != null) { 29 | return Scaffold( 30 | body: Onboarding( 31 | stats: stats, 32 | ), 33 | ); 34 | } else { 35 | return Scaffold( 36 | body: Center(child: CircularProgressIndicator()), 37 | ); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/pages/pages_import.dart: -------------------------------------------------------------------------------- 1 | export 'package:cached_network_image/cached_network_image.dart'; 2 | export 'package:google_fonts/google_fonts.dart'; 3 | export '../models/company_model.dart'; 4 | export 'package:url_launcher/url_launcher.dart'; 5 | export 'package:blt/src/routes/routing.dart'; 6 | export 'package:flutter_svg/flutter_svg.dart'; 7 | export '../components/onboarding/onboarding.dart'; 8 | export 'package:flutter_riverpod/flutter_riverpod.dart'; 9 | export 'package:blt/src/providers/authstate_provider.dart'; 10 | export '../util/api/general_api.dart'; 11 | export 'package:blt/src/util/api/auth_api.dart'; 12 | export 'package:blt/src/constants/about_constants.dart'; 13 | export 'package:blt/src/components/contributor_card.dart'; 14 | export 'package:flutter/services.dart'; 15 | export 'package:flutter_markdown/flutter_markdown.dart'; 16 | export 'package:font_awesome_flutter/font_awesome_flutter.dart'; 17 | export 'package:blt/src/constants/socialurls_constants.dart'; 18 | export 'package:blt/src/pages/home/issues.dart'; 19 | export 'package:blt/src/pages/home/leaderboard.dart'; 20 | export 'package:blt/src/pages/home/report_bug.dart'; 21 | export 'package:blt/src/pages/home/start_hunt.dart'; 22 | export 'package:blt/src/providers/login_provider.dart'; 23 | export 'package:blt/src/util/enums/login_type.dart'; 24 | export 'package:receive_sharing_intent/receive_sharing_intent.dart'; 25 | export 'package:blt/src/providers/issuelist_provider.dart'; 26 | export 'package:blt/src/util/api/user_api.dart'; 27 | export 'package:image_picker/image_picker.dart'; 28 | export 'dart:io'; 29 | export 'dart:math'; 30 | export 'package:blt/src/util/endpoints/general_endpoints.dart'; 31 | export 'package:flutter/gestures.dart'; 32 | export 'package:pasteboard/pasteboard.dart'; 33 | export 'package:blt/src/global/variables.dart'; 34 | export 'package:blt/src/pages/welcome.dart'; 35 | export 'package:flutter_gen/gen_l10n/app_localizations.dart'; 36 | export 'package:blt/src/providers/language_provider.dart'; 37 | export 'package:flutter/material.dart'; 38 | export 'package:blt/src/util/api/chatbot_api.dart'; 39 | export 'package:lottie/lottie.dart'; 40 | export '../models/bug_hunt_model.dart'; 41 | export 'package:blt/src/constants/monthname_constants.dart'; 42 | export 'package:blt/src/models/contributors_model.dart'; 43 | export 'package:blt/src/models/project_model.dart'; 44 | -------------------------------------------------------------------------------- /lib/src/pages/sizzle/sizzle_state_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 2 | 3 | // Define your providers here 4 | final usernameProvider = StateProvider((ref) => null); 5 | -------------------------------------------------------------------------------- /lib/src/pages/sizzle/sizzle_timer.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class TimerWidget extends StatefulWidget { 5 | const TimerWidget({Key? key}) : super(key: key); 6 | 7 | @override 8 | _TimerWidgetState createState() => _TimerWidgetState(); 9 | } 10 | 11 | class _TimerWidgetState extends State { 12 | late Timer _timer; 13 | Duration _elapsedTime = Duration.zero; 14 | 15 | @override 16 | void initState() { 17 | super.initState(); 18 | _startTimer(); 19 | } 20 | 21 | void _startTimer() { 22 | _timer = Timer.periodic(Duration(seconds: 1), (timer) { 23 | setState(() { 24 | _elapsedTime += Duration(seconds: 1); 25 | }); 26 | }); 27 | } 28 | 29 | @override 30 | void dispose() { 31 | _timer.cancel(); 32 | super.dispose(); 33 | } 34 | 35 | @override 36 | Widget build(BuildContext context) { 37 | final ThemeData theme = Theme.of(context); 38 | bool isDarkMode = theme.brightness == Brightness.dark; 39 | return Text( 40 | _formatDuration(_elapsedTime), 41 | style: TextStyle( 42 | color: isDarkMode ? Colors.white : Colors.black, fontSize: 16), 43 | ); 44 | } 45 | 46 | String _formatDuration(Duration duration) { 47 | String twoDigits(int n) => n.toString().padLeft(2, '0'); 48 | String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60)); 49 | String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60)); 50 | return '${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds'; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/src/pages/spam_call_blocker/database_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:sqflite/sqflite.dart'; 2 | import 'package:path/path.dart'; 3 | 4 | class DatabaseHelper { 5 | static Database? _database; 6 | 7 | // Create a singleton pattern 8 | static Future get database async { 9 | if (_database != null) return _database!; 10 | 11 | // If the database doesn't exist, create it 12 | _database = await _initDB(); 13 | return _database!; 14 | } 15 | 16 | // Initialize the database 17 | static Future _initDB() async { 18 | String path = join(await getDatabasesPath(), 'spam_numbers.db'); 19 | 20 | return await openDatabase( 21 | path, 22 | onCreate: (db, version) { 23 | return db.execute( 24 | 'CREATE TABLE numbers(id INTEGER PRIMARY KEY AUTOINCREMENT, number TEXT)', 25 | ); 26 | }, 27 | version: 1, 28 | ); 29 | } 30 | 31 | // Insert a number into the database 32 | static Future insertNumber(String number) async { 33 | final db = await database; 34 | await db.insert( 35 | 'numbers', 36 | {'number': number}, 37 | conflictAlgorithm: ConflictAlgorithm.replace, 38 | ); 39 | } 40 | 41 | // Get all numbers from the database 42 | static Future> getNumbers() async { 43 | final db = await database; 44 | final List> maps = await db.query('numbers'); 45 | 46 | return List.generate(maps.length, (i) { 47 | return maps[i]['number'] as String; 48 | }); 49 | } 50 | 51 | // Delete a number from the database 52 | static Future deleteNumber(String number) async { 53 | final db = await database; 54 | await db.delete( 55 | 'numbers', 56 | where: 'number = ?', 57 | whereArgs: [number], 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/src/providers/bug_hunt_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/providers/providers_imports.dart'; 2 | 3 | final bugHuntListProvider = 4 | StateNotifierProvider?>?>( 5 | (ref) { 6 | return BugHuntListProvider(ref.read); 7 | }, 8 | ); 9 | 10 | final prevBugHuntListProvider = StateNotifierProvider< 11 | PreviousBugHuntListProvider, AsyncValue?>?>( 12 | (ref) { 13 | return PreviousBugHuntListProvider(ref.read); 14 | }, 15 | ); 16 | 17 | class BugHuntListProvider extends StateNotifier?>?> { 18 | final Reader read; 19 | AsyncValue?>? previousState; 20 | 21 | BugHuntListProvider(this.read, [AsyncValue>? bugHuntList]) 22 | : super(bugHuntList ?? const AsyncValue.loading()) { 23 | _retrieveBugHuntsList(); 24 | } 25 | 26 | Future _retrieveBugHuntsList() async { 27 | try { 28 | final List? bugHunts = 29 | await BugHuntApiClient.getListOfActiveBugHunts(); 30 | state = AsyncValue.data(bugHunts); 31 | } catch (e) { 32 | AsyncValue.error(e); 33 | } 34 | } 35 | 36 | // Function call for refreshing state. 37 | Future refreshBugHuntList() async { 38 | state = const AsyncValue.loading(); 39 | try { 40 | await _retrieveBugHuntsList(); 41 | } catch (e) { 42 | AsyncValue.error(e); 43 | } 44 | } 45 | } 46 | 47 | class PreviousBugHuntListProvider 48 | extends StateNotifier?>?> { 49 | final Reader read; 50 | AsyncValue?>? previousState; 51 | 52 | PreviousBugHuntListProvider(this.read, 53 | [AsyncValue>? bugHuntList]) 54 | : super(bugHuntList ?? const AsyncValue.loading()) { 55 | _retrievePrevBugHuntsList(); 56 | } 57 | 58 | Future _retrievePrevBugHuntsList() async { 59 | try { 60 | final List? bugHunts = 61 | await BugHuntApiClient.getListOfPreviousBugHunts(); 62 | state = AsyncValue.data(bugHunts); 63 | } catch (e) { 64 | AsyncValue.error(e); 65 | } 66 | } 67 | 68 | // Function call for refreshing state. 69 | Future refreshPrevBugHuntList() async { 70 | state = const AsyncValue.loading(); 71 | try { 72 | await _retrievePrevBugHuntsList(); 73 | } catch (e) { 74 | AsyncValue.error(e); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/src/providers/companies/company_list_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/components/components_import.dart'; 2 | import 'package:blt/src/models/company_model.dart'; 3 | import 'package:blt/src/util/api/company_api.dart'; 4 | import 'package:http/http.dart' as http; 5 | 6 | final companiesListProvider = 7 | StateNotifierProvider?>?>( 8 | (ref) { 9 | return CompanyListNotifier(ref.read); 10 | }, 11 | ); 12 | 13 | class CompanyListNotifier extends StateNotifier?>?> { 14 | final Reader read; 15 | AsyncValue?>? previousState; 16 | 17 | CompanyListNotifier(this.read, [AsyncValue>? companyList]) 18 | : super(companyList ?? const AsyncValue.loading()) { 19 | _retrieveCompaniesList(); 20 | } 21 | 22 | Future _retrieveCompaniesList() async { 23 | final client = http.Client(); 24 | try { 25 | final List? companyData = 26 | await CompanyApiClient.getListOfCompanies(client, "companies/"); 27 | state = AsyncValue.data(companyData); 28 | } catch (e) { 29 | AsyncValue.error(e); 30 | } 31 | } 32 | 33 | Future refreshCompanyList() async { 34 | state = const AsyncValue.loading(); 35 | try { 36 | await _retrieveCompaniesList(); 37 | } catch (e) { 38 | AsyncValue.error(e); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/src/providers/dark_mode_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 3 | import 'package:shared_preferences/shared_preferences.dart'; 4 | 5 | final darkModeProvider = ChangeNotifierProvider((ref) { 6 | return DarkModeNotifier(); 7 | }); 8 | 9 | class DarkModeNotifier extends ChangeNotifier { 10 | static const _isDarkModeKey = 'isDarkMode'; 11 | 12 | bool _isDarkMode = false; 13 | 14 | bool get isDarkMode => _isDarkMode; 15 | 16 | DarkModeNotifier() { 17 | _loadDarkMode(); 18 | } 19 | 20 | Future _loadDarkMode() async { 21 | final prefs = await SharedPreferences.getInstance(); 22 | _isDarkMode = prefs.getBool(_isDarkModeKey) ?? false; 23 | notifyListeners(); 24 | } 25 | 26 | Future toggleDarkMode() async { 27 | _isDarkMode = !_isDarkMode; 28 | notifyListeners(); 29 | 30 | final prefs = await SharedPreferences.getInstance(); 31 | prefs.setBool(_isDarkModeKey, _isDarkMode); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/src/providers/language_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 2 | import 'package:shared_preferences/shared_preferences.dart'; 3 | 4 | final languageProvider = 5 | StateNotifierProvider((ref) { 6 | return LanguageStateNotifier(); 7 | }); 8 | 9 | class LanguageStateNotifier extends StateNotifier { 10 | LanguageStateNotifier() : super('en') { 11 | _loadSavedLanguage(); 12 | } 13 | 14 | Future _loadSavedLanguage() async { 15 | final prefs = await SharedPreferences.getInstance(); 16 | final savedLang = prefs.getString('saved_language') ?? 17 | 'en'; // Default to English if no saved preference 18 | state = savedLang; 19 | } 20 | 21 | Future changeLanguage(String newLanguageCode) async { 22 | final prefs = await SharedPreferences.getInstance(); 23 | await prefs.setString('saved_language', newLanguageCode); 24 | state = newLanguageCode; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/providers/leaderboards/companyscoreboard_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/providers/providers_imports.dart'; 2 | import 'package:http/http.dart' as http; 3 | 4 | /// The provider which exposes the state management 5 | /// for companies in the company scoreboard list. 6 | final companyScoreboardProvider = StateNotifierProvider< 7 | CompanyScoreboardNotifier, AsyncValue?>?>((ref) { 8 | return CompanyScoreboardNotifier(ref.read); 9 | }); 10 | 11 | class CompanyScoreboardNotifier 12 | extends StateNotifier?>?> { 13 | final Reader read; 14 | 15 | AsyncValue?>? previousState; 16 | 17 | CompanyScoreboardNotifier(this.read, [AsyncValue>? companyList]) 18 | : super(companyList ?? const AsyncValue.loading()) { 19 | _retrieveCompanyList(); 20 | } 21 | 22 | /// Default call for getting companies 23 | /// when the provider is initialized. 24 | Future _retrieveCompanyList() async { 25 | try { 26 | final List? companyData = 27 | await LeaderboardApiClient.getScoreBoardData( 28 | http.Client(), 29 | LeaderboardEndpoints.companyScoreboard, 30 | ); 31 | 32 | state = AsyncValue.data(companyData); 33 | } catch (e) { 34 | AsyncValue.error(e); 35 | } 36 | } 37 | 38 | /// Function call for refreshing state. 39 | Future refreshCompanyList() async { 40 | state = const AsyncValue.loading(); 41 | try { 42 | await _retrieveCompanyList(); 43 | } catch (e) { 44 | AsyncValue.error(e); 45 | } 46 | } 47 | 48 | /// Caches the current state to prevent errors. 49 | // void _cacheState() { 50 | // previousState = state; 51 | // } 52 | 53 | /// Resets the state to previous stored state. 54 | // void _resetState() { 55 | // if (previousState != null) { 56 | // state = previousState; 57 | // previousState = null; 58 | // } 59 | // } 60 | 61 | /// Exception handler for state exception, 62 | /// resets to last state on error. 63 | // void _handleException(e) { 64 | // print(e); 65 | // _resetState(); 66 | // } 67 | } 68 | -------------------------------------------------------------------------------- /lib/src/providers/leaderboards/globalleaderboard_povider.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/providers/providers_imports.dart'; 2 | import 'package:http/http.dart' as http; 3 | 4 | /// The provider which exposes the state management 5 | /// for users in the global leaderboard list. 6 | final globalLeaderBoardProvider = StateNotifierProvider< 7 | GlobalLeaderBoardNotifier, AsyncValue?>?>((ref) { 8 | return GlobalLeaderBoardNotifier(ref.read); 9 | }); 10 | 11 | class GlobalLeaderBoardNotifier 12 | extends StateNotifier?>?> { 13 | final Reader read; 14 | AsyncValue?>? previousState; 15 | 16 | GlobalLeaderBoardNotifier(this.read, [AsyncValue>? leaderList]) 17 | : super(leaderList ?? const AsyncValue.loading()) { 18 | _retrieveLeaderList(); 19 | } 20 | 21 | /// Default call for getting users in leaderboard 22 | /// when the provider is initialized. 23 | Future _retrieveLeaderList() async { 24 | try { 25 | final List? leaderData = 26 | await LeaderboardApiClient.getLeaderData( 27 | http.Client(), 28 | LeaderboardEndpoints.globalLeaderboard, 29 | ); 30 | 31 | state = AsyncValue.data(leaderData); 32 | } catch (e) { 33 | AsyncValue.error(e); 34 | } 35 | } 36 | 37 | /// Function call for refreshing state. 38 | Future refreshLeaderList() async { 39 | state = const AsyncValue.loading(); 40 | try { 41 | await _retrieveLeaderList(); 42 | } catch (e) { 43 | AsyncValue.error(e); 44 | } 45 | } 46 | 47 | /// Caches the current state to prevent errors. 48 | // void _cacheState() { 49 | // previousState = state; 50 | // } 51 | 52 | /// Resets the state to previous stored state. 53 | // void _resetState() { 54 | // if (previousState != null) { 55 | // state = previousState; 56 | // previousState = null; 57 | // } 58 | // } 59 | 60 | /// Exception handler for state exception, 61 | /// resets to last state on error. 62 | // void _handleException(e) { 63 | // print(e); 64 | // _resetState(); 65 | // } 66 | } 67 | -------------------------------------------------------------------------------- /lib/src/providers/leaderboards/monthlyleaderboard_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/models/leaderdata_model.dart'; 2 | import 'package:blt/src/providers/providers_imports.dart'; 3 | import 'package:http/http.dart' as http; 4 | 5 | final monthlyLeaderBoardProvider = StateNotifierProvider< 6 | MonthlyLeaderBoardNotifier, AsyncValue?>?>((ref) { 7 | return MonthlyLeaderBoardNotifier(ref.read); 8 | }); 9 | 10 | class MonthlyLeaderBoardNotifier 11 | extends StateNotifier?>?> { 12 | final Reader read; 13 | String? nextUrl; 14 | AsyncValue?>? previousState; 15 | 16 | MonthlyLeaderBoardNotifier(this.read, [AsyncValue>? leaderList]) 17 | : super(leaderList ?? const AsyncValue.loading()) { 18 | _retrieveMonthlyLeaderList(DateTime.now().year, DateTime.now().month); 19 | } 20 | 21 | Future _retrieveMonthlyLeaderList(int? year, int? month) async { 22 | try { 23 | final LeaderData? monthlyLeaderData = 24 | await LeaderboardApiClient.getMonthlyLeaderData( 25 | http.Client(), 26 | LeaderboardEndpoints.monthly_leaderboard, 27 | year, 28 | month, 29 | ); 30 | nextUrl = monthlyLeaderData!.nextQuery; 31 | state = AsyncValue.data(monthlyLeaderData.leaderList); 32 | } catch (e) { 33 | AsyncValue.error(e); 34 | } 35 | } 36 | 37 | Future getMoreMontlyLeaders() async { 38 | _cacheState(); 39 | try { 40 | final LeaderData leaderData = 41 | await LeaderboardApiClient.getMoreMonthlyLeaders(nextUrl); 42 | nextUrl = leaderData.nextQuery; 43 | state = state!.whenData((leaderList) { 44 | leaderList!.addAll(leaderData.leaderList!); 45 | return leaderList; 46 | }); 47 | } catch (e) { 48 | _handleException(e); 49 | } 50 | } 51 | 52 | Future refreshMonthlyLeaderList(int? year, int? month) async { 53 | state = const AsyncValue.loading(); 54 | try { 55 | await _retrieveMonthlyLeaderList(year, month); 56 | } catch (e) { 57 | AsyncValue.error(e); 58 | } 59 | } 60 | 61 | /// Caches the current state to prevent errors. 62 | void _cacheState() { 63 | previousState = state; 64 | } 65 | 66 | void _resetState() { 67 | if (previousState != null) { 68 | state = previousState; 69 | previousState = null; 70 | } 71 | } 72 | 73 | void _handleException(e) { 74 | print(e); 75 | _resetState(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/src/providers/login_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/providers/providers_imports.dart'; 2 | 3 | /// The provider which exposes the state management for 4 | /// the type of login (guest or user or logged out). 5 | final loginProvider = StateNotifierProvider((ref) { 6 | return LoginNotifier(ref.read); 7 | }); 8 | 9 | class LoginNotifier extends StateNotifier { 10 | final Reader read; 11 | LoginNotifier(this.read, [LoginType? state]) 12 | : super(state ?? LoginType.loggedOut); 13 | 14 | /// Set login state to guest type. 15 | void setGuestLogin() { 16 | state = LoginType.guest; 17 | } 18 | 19 | /// Set login state to user type. 20 | void setUserLogin() { 21 | state = LoginType.user; 22 | } 23 | 24 | /// Set login state to logged out. 25 | void logout() { 26 | state = LoginType.loggedOut; 27 | } 28 | 29 | /// Getter for current login state. 30 | LoginType get loginType => state; 31 | } 32 | -------------------------------------------------------------------------------- /lib/src/providers/projects_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/providers/providers_imports.dart'; 2 | import 'package:blt/src/util/api/project_apis.dart'; 3 | 4 | final projectListProvider = 5 | StateNotifierProvider?>?>( 6 | (ref) { 7 | return ProjectListProvider(ref.read); 8 | }); 9 | 10 | class ProjectListProvider extends StateNotifier?>?> { 11 | final Reader read; 12 | AsyncValue?>? previousState; 13 | 14 | ProjectListProvider(this.read, [AsyncValue>? projectList]) 15 | : super(projectList ?? const AsyncValue.loading()) { 16 | _retrieveProjectList(); 17 | } 18 | 19 | Future _retrieveProjectList() async { 20 | try { 21 | final List? projects = await ProjectAPiClient.getAllProjects(); 22 | state = AsyncValue.data(projects); 23 | } catch (e) { 24 | AsyncValue.error(e); 25 | } 26 | } 27 | 28 | Future refreshProjectList() async { 29 | state = const AsyncValue.loading(); 30 | try { 31 | await _retrieveProjectList(); 32 | } catch (e) { 33 | AsyncValue.error(e); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/src/providers/providers_imports.dart: -------------------------------------------------------------------------------- 1 | export 'package:blt/src/util/enums/login_type.dart'; 2 | export 'package:flutter_riverpod/flutter_riverpod.dart'; 3 | export '../models/issue_model.dart'; 4 | export '../models/issuedata_model.dart'; 5 | export '../util/api/issues_api.dart'; 6 | export '../util/endpoints/issue_endpoints.dart'; 7 | export 'package:blt/src/pages/welcome.dart'; 8 | export 'package:blt/src/util/api/user_api.dart'; 9 | export 'package:flutter/material.dart'; 10 | export 'package:flutter_secure_storage/flutter_secure_storage.dart'; 11 | export './login_provider.dart'; 12 | export '../models/user_model.dart'; 13 | export '../routes/routing.dart'; 14 | export '../global/variables.dart'; 15 | export '../util/api/auth_api.dart'; 16 | export '../util/enums/authstate_type.dart'; 17 | export 'package:blt/src/models/company_model.dart'; 18 | export 'package:blt/src/util/api/leaderboard_api.dart'; 19 | export 'package:blt/src/util/endpoints/leaderboard_endpoints.dart'; 20 | export 'package:blt/src/models/leader_model.dart'; 21 | export 'package:blt/src/models/bug_hunt_model.dart'; 22 | export 'package:blt/src/util/api/bug_hunt_api.dart'; 23 | export 'package:blt/src/models/contributors_model.dart'; 24 | export 'package:blt/src/models/project_model.dart'; 25 | export 'package:blt/src/util/api/github_apis.dart'; 26 | -------------------------------------------------------------------------------- /lib/src/routes/routes_import.dart: -------------------------------------------------------------------------------- 1 | export 'package:blt/src/models/issue_model.dart'; 2 | export 'package:blt/src/pages/auth/forgot.dart'; 3 | export 'package:blt/src/pages/auth/signup.dart'; 4 | export 'package:blt/src/pages/drawer/change_password.dart'; 5 | export 'package:blt/src/pages/error.dart'; 6 | export 'package:blt/src/pages/home/home.dart'; 7 | export 'package:blt/src/pages/drawer/legal.dart'; 8 | export 'package:blt/src/pages/auth/login.dart'; 9 | export 'package:blt/src/pages/home/profile.dart'; 10 | export 'package:flutter/material.dart'; 11 | export '../models/company_model.dart'; 12 | export '../pages/company_details.dart'; 13 | export '../pages/drawer/company_dashboard.dart'; 14 | export '../pages/drawer/referral.dart'; 15 | export '../pages/welcome.dart'; 16 | export '../pages/drawer/about.dart'; 17 | export '../pages/leaderboards/company_scoreboard.dart'; 18 | export '../pages/leaderboards/global_leaderboard.dart'; 19 | export '../pages/issues/issue_detail.dart'; 20 | export '../pages/leaderboards/monthly_leaderboard.dart'; 21 | export '../pages/drawer/social.dart'; 22 | export 'package:blt/src/pages/companies/company_details_and_issues.dart'; 23 | export 'package:blt/src/pages/companies/company_list_page.dart'; 24 | export 'package:blt/src/pages/issues/closed_issues.dart'; 25 | export 'package:blt/src/pages/issues/open_issues.dart'; 26 | export 'package:blt/src/pages/chat_bot_page.dart'; 27 | export 'package:blt/src/pages/drawer/sponsor_page.dart'; 28 | export 'package:blt/src/models/bug_hunt_model.dart'; 29 | export 'package:blt/src/pages/bug_hunt_desc_page.dart'; 30 | export 'package:blt/src/pages/drawer/prev_bug_hunts.dart'; 31 | export 'package:blt/src/pages/drawer/show_bug_hunts.dart'; 32 | export 'package:blt/src/models/project_model.dart'; 33 | export 'package:blt/src/pages/contributors_info.dart'; 34 | export 'package:blt/src/pages/drawer/projects.dart'; 35 | export 'package:blt/src/pages/sizzle/sizzle_login.dart'; 36 | export 'package:blt/src/pages/sizzle/sizzle_home.dart'; 37 | export '../pages/spam_call_blocker/blocker_home.dart'; 38 | -------------------------------------------------------------------------------- /lib/src/util/api/chatbot_api.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:blt/src/pages/home/home_imports.dart'; 3 | import 'package:http/http.dart' as http; 4 | 5 | class ChatBotApiClient { 6 | ChatBotApiClient._(); 7 | 8 | static Future getResponse(String query) async { 9 | try { 10 | var link = GeneralEndPoints.baseUrl + "api/chatbot/conversation/"; 11 | var response = await http.post( 12 | Uri.parse(link), 13 | headers: {"parses": "application/json", "renders": "application/json"}, 14 | body: {"question": query}, 15 | ); 16 | 17 | var json = jsonDecode(response.body); 18 | if (json["answer"] == "" || json["answer"] == null) 19 | return "err: ${json["error"]}"; 20 | 21 | return "res: ${json["answer"]}"; 22 | } catch (e) { 23 | return "err: $e"; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/util/api/company_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/util/util_import.dart'; 2 | import 'package:http/http.dart' as http; 3 | 4 | /// CLass for accessing the company client. 5 | class CompanyApiClient { 6 | CompanyApiClient._(); 7 | 8 | static Future> getListOfCompanies( 9 | http.Client client, String endpoint) async { 10 | String searchUrl = GeneralEndPoints.apiBaseUrl + endpoint; 11 | List companiesList = []; 12 | try { 13 | var response = await client.get(Uri.parse(searchUrl)); 14 | var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)); 15 | companiesList = Company.fromSnapshot(decodedResponse["results"]); 16 | } catch (e) { 17 | print(e); 18 | } 19 | return companiesList; 20 | } 21 | 22 | /// Search a company by keyword, 23 | /// returns the first matching result. 24 | static Future getCompanyByKeyWord( 25 | http.Client client, String paginated_url, String keyword) async { 26 | String searchUrl = paginated_url + "?search=$keyword"; 27 | // print(searchUrl); 28 | try { 29 | var response = await client.get(Uri.parse(searchUrl)); 30 | var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)); 31 | var companyJson = Company.fromJson(decodedResponse["results"][0]); 32 | return companyJson; 33 | } catch (e) { 34 | print(e); 35 | } 36 | return null; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/src/util/api/github_apis.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:blt/src/models/contributors_model.dart'; 3 | import 'package:http/http.dart' as http; 4 | 5 | class GithubApis { 6 | GithubApis._(); 7 | 8 | static Future> getContributors( 9 | String projectName, String ownerName) async { 10 | String searchUrl = 11 | "https://api.github.com/repos/$ownerName/$projectName/contributors"; 12 | List contributors = []; 13 | try { 14 | var response = await http.get( 15 | Uri.parse( 16 | searchUrl, 17 | ), 18 | ); 19 | var json = jsonDecode(response.body); 20 | contributors = Contributors.fromSnapshot(json); 21 | } catch (e) { 22 | print(e); 23 | } 24 | return contributors; 25 | } 26 | 27 | static Future getContributorsInfoFromID(int id) async { 28 | String searchUrl = "https://api.github.com/user/$id"; 29 | Contributors? contributors; 30 | try { 31 | var response = await http.get( 32 | Uri.parse( 33 | searchUrl, 34 | ), 35 | ); 36 | var json = jsonDecode(response.body); 37 | print(json); 38 | contributors = Contributors.fromJson(json); 39 | } catch (e) { 40 | print(e); 41 | } 42 | return contributors; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/src/util/api/leaderboard_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:http/http.dart' as http; 2 | import 'package:blt/src/util/util_import.dart'; 3 | 4 | class LeaderboardApiClient { 5 | LeaderboardApiClient._(); 6 | 7 | static Future> getLeaderData( 8 | http.Client client, String paginatedUrl) async { 9 | return client 10 | .get( 11 | Uri.parse(paginatedUrl), 12 | ) 13 | .then((var response) { 14 | List leaders = 15 | (json.decode(utf8.decode(response.bodyBytes)) as List) 16 | .map((data) => Leaders.fromJson(data)) 17 | .toList(); 18 | return leaders; 19 | }); 20 | } 21 | 22 | static Future getMonthlyLeaderData( 23 | http.Client client, String paginatedUrl, int? year, int? month) async { 24 | final queryParams = { 25 | "filter": '1', 26 | "year": year.toString(), 27 | "month": month.toString(), 28 | }; 29 | // print(Uri.parse(paginatedUrl).replace(queryParameters: queryParams)); 30 | return client 31 | .get( 32 | Uri.parse(paginatedUrl).replace(queryParameters: queryParams), 33 | ) 34 | .then((var response) { 35 | List leaderList = []; 36 | var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)); 37 | decodedResponse["results"].forEach((element) { 38 | leaderList.add(Leaders.fromJson(element)); 39 | }); 40 | LeaderData leaderData = LeaderData( 41 | count: decodedResponse["count"], 42 | nextQuery: decodedResponse["next"], 43 | previousQuery: decodedResponse["previous"], 44 | leaderList: leaderList, 45 | ); 46 | return leaderData; 47 | }); 48 | } 49 | 50 | static Future getMoreMonthlyLeaders(String? nextUrl) async { 51 | return http 52 | .get( 53 | Uri.parse(nextUrl!), 54 | ) 55 | .then((var response) { 56 | List leaderList = []; 57 | var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)); 58 | decodedResponse["results"].forEach((element) { 59 | leaderList.add(Leaders.fromJson(element)); 60 | }); 61 | LeaderData leaderData = LeaderData( 62 | count: decodedResponse["count"], 63 | nextQuery: decodedResponse["next"], 64 | previousQuery: decodedResponse["previous"], 65 | leaderList: leaderList, 66 | ); 67 | return leaderData; 68 | }); 69 | } 70 | 71 | static Future> getScoreBoardData( 72 | http.Client client, String? paginatedUrl) async { 73 | var req = await client.get( 74 | Uri.parse(paginatedUrl!), 75 | ); 76 | var response = jsonDecode(req.body); 77 | return (response["results"] as List) 78 | .map((data) => Company.fromJson(data)) 79 | .toList(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/src/util/api/project_apis.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/models/project_model.dart'; 2 | import 'package:http/http.dart' as http; 3 | 4 | import '../util_import.dart'; 5 | 6 | class ProjectAPiClient { 7 | ProjectAPiClient._(); 8 | 9 | static Future?> getAllProjects( 10 | {http.Client? testClient}) async { 11 | List projects = []; 12 | try { 13 | var uri = GeneralEndPoints.apiBaseUrl + "projects/"; 14 | var response = (testClient != null) 15 | ? await testClient.get(Uri.parse(uri)) 16 | : await http.get(Uri.parse(uri)); 17 | var json_res = json.decode(response.body); 18 | projects = Project.fromSnapshot(json_res['projects']); 19 | } catch (e) { 20 | print(projects); 21 | print(e); 22 | } 23 | return projects; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/src/util/api/tags_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/util/util_import.dart'; 2 | import 'package:http/http.dart' as http; 3 | 4 | class TagsApiClient { 5 | TagsApiClient._(); 6 | static Future> getListOfTags() async { 7 | List tags = []; 8 | try { 9 | var response = await http.get( 10 | Uri.parse(GeneralEndPoints.apiBaseUrl + "tags"), 11 | headers: {"content-type": "application/json"}, 12 | ); 13 | var json = jsonDecode(response.body); 14 | tags = Tag.fromSnapshot(json["results"]); 15 | } catch (e) { 16 | print(e); 17 | } 18 | return tags; 19 | } 20 | 21 | Future postTag(String name, BuildContext context) async { 22 | try { 23 | var response = await http.post( 24 | Uri.parse(GeneralEndPoints.apiBaseUrl + "tags"), 25 | headers: {"content-type": "application/json"}, 26 | body: {"name": name}, 27 | ); 28 | if (response.statusCode == 201 || response.statusCode == 200) { 29 | SnackBar thankSnack = SnackBar( 30 | content: Text("New tag created successfully!"), 31 | ); 32 | ScaffoldMessenger.of(context).showSnackBar(thankSnack); 33 | } else { 34 | ScaffoldMessenger.of(context).clearSnackBars(); 35 | SnackBar errorSnack = SnackBar( 36 | content: 37 | Text("There was some error, please try again!" + response.body), 38 | ); 39 | print(response.body); 40 | ScaffoldMessenger.of(context).showSnackBar(errorSnack); 41 | } 42 | } catch (e) { 43 | print(e); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/src/util/api/user_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/util/util_import.dart'; 2 | import 'package:http/http.dart' as http; 3 | 4 | class UserApiClient { 5 | UserApiClient._(); 6 | 7 | /// Get a user's details from username and token, 8 | /// used for currentUser. 9 | static Future getUserDetails(http.Client client, User user) async { 10 | http.Response? response; 11 | try { 12 | response = await http.get( 13 | Uri.parse(UserEndPoints.userData), 14 | headers: { 15 | "username": user.username!, 16 | "token": user.token!, 17 | }, 18 | ); 19 | print(response.body); 20 | } catch (e) {} 21 | } 22 | 23 | /// Get a user's details, queried 24 | /// against a [user]'s username. 25 | static Future getUserInfo(http.Client client, User user) async { 26 | try { 27 | String searchUrl = UserEndPoints.userInfo + "?search=${user.username}"; 28 | var response = await client.get( 29 | Uri.parse(searchUrl), 30 | headers: { 31 | "Authorization": "Token ${user.token}", 32 | }, 33 | ); 34 | var decodedResponse = 35 | jsonDecode(utf8.decode(response.bodyBytes))["results"][0]; 36 | // user.id = decodedResponse["user"]["id"]; 37 | user.pfpLink = decodedResponse["user_avatar"]; 38 | user.title = decodedResponse["title"]; 39 | user.email = decodedResponse["email"]; 40 | user.winning = decodedResponse["winnings"]; 41 | user.description = decodedResponse["description"]; 42 | user.following = decodedResponse["follows"] as List? ?? []; 43 | user.likedIssueId = decodedResponse["issue_upvoted"] as List? ?? []; 44 | user.savedIssueId = decodedResponse["issue_saved"] as List? ?? []; 45 | user.totalScore = decodedResponse["total_score"]; 46 | return user; 47 | } catch (e) { 48 | print(e); 49 | } 50 | return null; 51 | } 52 | 53 | static Future updatePfp(XFile image, User user) async { 54 | try { 55 | String updateUrl = "${UserEndPoints.userInfo}${user.id}/"; 56 | 57 | final uri = Uri.parse(updateUrl); 58 | var request = new http.MultipartRequest('PUT', uri); 59 | final httpImage = await http.MultipartFile.fromPath( 60 | 'user_avatar', image.path, 61 | filename: image.name); 62 | request.files.add(httpImage); 63 | request.headers.addAll( 64 | { 65 | "Authorization": "Token ${user.token}", 66 | }, 67 | ); 68 | var streamedResponse = await request.send(); 69 | var response = await http.Response.fromStream(streamedResponse); 70 | var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)); 71 | user.pfpLink = decodedResponse["user_avatar"]; 72 | } catch (e) { 73 | print(e); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/src/util/endpoints/auth_endpoints.dart: -------------------------------------------------------------------------------- 1 | import 'general_endpoints.dart'; 2 | 3 | /// Class to access the API's authentication endpoints. 4 | class AuthEndPoints { 5 | AuthEndPoints._(); 6 | 7 | static const String authBaseUrl = GeneralEndPoints.baseUrl + "auth/"; 8 | 9 | static const String emailpasswordLogin = 10 | GeneralEndPoints.baseUrl + "authenticate/"; 11 | 12 | static const String logout = authBaseUrl + "logout/"; 13 | 14 | static const String register = authBaseUrl + "registration/"; 15 | 16 | static const String reset = authBaseUrl + "password/reset/"; 17 | 18 | static const String change = authBaseUrl + "password/change/"; 19 | } 20 | -------------------------------------------------------------------------------- /lib/src/util/endpoints/company_endpoints.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/util/endpoints/general_endpoints.dart'; 2 | 3 | /// Class for API endpoints needed to access companies/domains on BLT. 4 | class CompanyEndpoints { 5 | CompanyEndpoints._(); 6 | 7 | static const String domain = GeneralEndPoints.apiBaseUrl + "domain/"; 8 | } 9 | -------------------------------------------------------------------------------- /lib/src/util/endpoints/general_endpoints.dart: -------------------------------------------------------------------------------- 1 | /// Class to access the General endpoints. 2 | class GeneralEndPoints { 3 | GeneralEndPoints._(); 4 | 5 | static const String domain = "blt.owasp.org/api/"; 6 | 7 | static const String baseUrl = "https://blt.owasp.org/"; 8 | 9 | static const String apiBaseUrl = baseUrl + "api/v1/"; 10 | 11 | static const String stats = apiBaseUrl + "stats/"; 12 | 13 | static const String duplicateURL = apiBaseUrl + "urlcheck/"; 14 | 15 | static const String contributors = apiBaseUrl + "contributors/"; 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/util/endpoints/issue_endpoints.dart: -------------------------------------------------------------------------------- 1 | import 'general_endpoints.dart'; 2 | 3 | /// Class for API endpoints to access issues on BLT. 4 | class IssueEndPoints { 5 | IssueEndPoints._(); 6 | 7 | static const String issues = GeneralEndPoints.apiBaseUrl + "issues/"; 8 | 9 | static const String userIssues = GeneralEndPoints.apiBaseUrl + "userissues/"; 10 | 11 | static const String likeIssues = GeneralEndPoints.apiBaseUrl + "issue/like/"; 12 | 13 | static const String flagIssues = GeneralEndPoints.apiBaseUrl + "issue/flag/"; 14 | } 15 | -------------------------------------------------------------------------------- /lib/src/util/endpoints/leaderboard_endpoints.dart: -------------------------------------------------------------------------------- 1 | import 'general_endpoints.dart'; 2 | 3 | class LeaderboardEndpoints { 4 | LeaderboardEndpoints._(); 5 | 6 | static const String globalLeaderboard = 7 | GeneralEndPoints.apiBaseUrl + "userscore/"; 8 | 9 | static const String monthly_leaderboard = 10 | GeneralEndPoints.apiBaseUrl + "leaderboard/"; 11 | 12 | static const String companyScoreboard = 13 | GeneralEndPoints.apiBaseUrl + "leaderboard/?leaderboard_type=companies"; 14 | } 15 | -------------------------------------------------------------------------------- /lib/src/util/endpoints/user_endpoints.dart: -------------------------------------------------------------------------------- 1 | import 'general_endpoints.dart'; 2 | 3 | /// Class for API endpoints needed to access users data on BLT. 4 | class UserEndPoints { 5 | UserEndPoints._(); 6 | 7 | static const String userInfo = GeneralEndPoints.apiBaseUrl + "profile/"; 8 | 9 | static const String userData = 10 | GeneralEndPoints.apiBaseUrl + "profile/auth/user/"; 11 | } 12 | -------------------------------------------------------------------------------- /lib/src/util/enums/authstate_type.dart: -------------------------------------------------------------------------------- 1 | /// Types of Authentication States possible. 2 | enum AuthState { 3 | authenticating, 4 | loggedIn, 5 | loggedOut, 6 | error, 7 | } 8 | -------------------------------------------------------------------------------- /lib/src/util/enums/login_type.dart: -------------------------------------------------------------------------------- 1 | /// Types of Login States possible. 2 | enum LoginType { 3 | guest, 4 | user, 5 | loggedOut, 6 | } 7 | -------------------------------------------------------------------------------- /lib/src/util/services/init_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | class InitService { 5 | static void init(BuildContext context) { 6 | WidgetsBinding.instance.addPostFrameCallback((_) { 7 | _setOrientation(context); 8 | }); 9 | } 10 | 11 | static void _setOrientation(BuildContext context) { 12 | final shortestSide = MediaQuery.of(context).size.shortestSide; 13 | if (shortestSide > 600) { 14 | SystemChrome.setPreferredOrientations([ 15 | DeviceOrientation.portraitUp, 16 | DeviceOrientation.portraitDown, 17 | DeviceOrientation.landscapeLeft, 18 | DeviceOrientation.landscapeRight, 19 | ]); 20 | } else { 21 | SystemChrome.setPreferredOrientations([ 22 | DeviceOrientation.portraitUp, 23 | ]); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/util/services/permission_handlers.dart: -------------------------------------------------------------------------------- 1 | import 'package:permission_handler/permission_handler.dart'; 2 | 3 | Future requestStoragePermission() async { 4 | if (await Permission.photos.request().isGranted) { 5 | return; 6 | } else if (await Permission.photos.request().isDenied) { 7 | return; 8 | } else { 9 | Permission.photos.request(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/src/util/services/shared_preferences.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:blt/src/util/util_import.dart'; 4 | import 'package:shared_preferences/shared_preferences.dart'; 5 | 6 | class UserPreferences { 7 | Future saveUser(User user) async { 8 | final SharedPreferences prefs = await SharedPreferences.getInstance(); 9 | 10 | prefs.setInt("id", user.id ?? 0); 11 | prefs.setString("username", user.username ?? ""); 12 | prefs.setString("email", user.email ?? ""); 13 | prefs.setString("token", user.token ?? ""); 14 | 15 | return true; 16 | } 17 | 18 | Future getUser() async { 19 | final SharedPreferences prefs = await SharedPreferences.getInstance(); 20 | 21 | int id = prefs.getInt("id")!; 22 | String username = prefs.getString("username")!; 23 | String email = prefs.getString("email")!; 24 | String token = prefs.getString("token")!; 25 | 26 | return User( 27 | id: id, 28 | username: username, 29 | email: email, 30 | token: token, 31 | ); 32 | } 33 | 34 | void removeUser() async { 35 | final SharedPreferences prefs = await SharedPreferences.getInstance(); 36 | prefs.remove("email"); 37 | prefs.remove("username"); 38 | prefs.remove("id"); 39 | prefs.remove("token"); 40 | } 41 | 42 | Future getToken(args) async { 43 | final SharedPreferences prefs = await SharedPreferences.getInstance(); 44 | String token = prefs.getString("token")!; 45 | return token; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/src/util/theme_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AppTheme { 4 | static ThemeData lightTheme = ThemeData( 5 | useMaterial3: true, 6 | primarySwatch: Colors.red, 7 | primaryColor: Colors.white, 8 | visualDensity: VisualDensity.adaptivePlatformDensity, 9 | brightness: Brightness.light); 10 | 11 | static ThemeData darkTheme = ThemeData.dark( 12 | useMaterial3: true, 13 | ).copyWith(brightness: Brightness.dark); 14 | } 15 | -------------------------------------------------------------------------------- /lib/src/util/util_import.dart: -------------------------------------------------------------------------------- 1 | export 'package:blt/src/models/user_model.dart'; 2 | export 'package:blt/src/util/endpoints/auth_endpoints.dart'; 3 | export 'package:blt/src/util/endpoints/company_endpoints.dart'; 4 | export 'package:blt/src/util/endpoints/general_endpoints.dart'; 5 | export 'package:blt/src/global/variables.dart'; 6 | export 'package:blt/src/routes/routing.dart'; 7 | export 'package:blt/src/util/endpoints/issue_endpoints.dart'; 8 | export 'package:blt/src/models/company_model.dart'; 9 | export 'package:blt/src/models/leaderdata_model.dart'; 10 | export 'package:blt/src/util/endpoints/user_endpoints.dart'; 11 | export 'package:image_picker/image_picker.dart'; 12 | export 'package:blt/src/models/leader_model.dart'; 13 | export 'package:blt/src/models/issuedata_model.dart'; 14 | export 'package:blt/src/models/issue_model.dart'; 15 | export 'dart:convert'; 16 | export 'package:blt/src/models/tags_model.dart'; 17 | export 'package:flutter/material.dart'; 18 | -------------------------------------------------------------------------------- /lib/src/util/validators.dart: -------------------------------------------------------------------------------- 1 | String? validateEmail(String? value) { 2 | RegExp regex = new RegExp( 3 | r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'); 4 | if (value == null || value.isEmpty) { 5 | return "Your email is required"; 6 | } else if (!regex.hasMatch(value)) { 7 | return "Please provide a valid emal address"; 8 | } 9 | return null; 10 | } 11 | 12 | String? validatePassword(String? value) { 13 | RegExp regex = new RegExp( 14 | r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!#%*?&]{8,20}$'); 15 | if (value == null || value.isEmpty) { 16 | return "Your Password is required"; 17 | } else if (!regex.hasMatch(value)) { 18 | return "Please provide a valid Password!\n1. Password length should be in range (8, 20)\n2. Password must contain atleast a LowerCase Letter\n3.Password must contain atleast a UpperCase Leter\n4.Password must contain atleast a numerical digit\n5.Password must contain atleast a special character \n(\$, @, #, %)"; 19 | } 20 | return null; 21 | } 22 | -------------------------------------------------------------------------------- /linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | void fl_register_plugins(FlPluginRegistry* registry) { 18 | g_autoptr(FlPluginRegistrar) awesome_notifications_registrar = 19 | fl_plugin_registry_get_registrar_for_plugin(registry, "AwesomeNotificationsPlugin"); 20 | awesome_notifications_plugin_register_with_registrar(awesome_notifications_registrar); 21 | g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = 22 | fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); 23 | file_selector_plugin_register_with_registrar(file_selector_linux_registrar); 24 | g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = 25 | fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); 26 | flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); 27 | g_autoptr(FlPluginRegistrar) local_notifier_registrar = 28 | fl_plugin_registry_get_registrar_for_plugin(registry, "LocalNotifierPlugin"); 29 | local_notifier_plugin_register_with_registrar(local_notifier_registrar); 30 | g_autoptr(FlPluginRegistrar) pasteboard_registrar = 31 | fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin"); 32 | pasteboard_plugin_register_with_registrar(pasteboard_registrar); 33 | g_autoptr(FlPluginRegistrar) sentry_flutter_registrar = 34 | fl_plugin_registry_get_registrar_for_plugin(registry, "SentryFlutterPlugin"); 35 | sentry_flutter_plugin_register_with_registrar(sentry_flutter_registrar); 36 | g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = 37 | fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); 38 | url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); 39 | } 40 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | awesome_notifications 7 | file_selector_linux 8 | flutter_secure_storage_linux 9 | local_notifier 10 | pasteboard 11 | sentry_flutter 12 | url_launcher_linux 13 | ) 14 | 15 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 16 | ) 17 | 18 | set(PLUGIN_BUNDLED_LIBRARIES) 19 | 20 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 21 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 22 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 23 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 25 | endforeach(plugin) 26 | 27 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 28 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 29 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 30 | endforeach(ffi_plugin) 31 | -------------------------------------------------------------------------------- /linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import awesome_notifications 9 | import file_selector_macos 10 | import flutter_secure_storage_macos 11 | import local_notifier 12 | import package_info_plus 13 | import pasteboard 14 | import path_provider_foundation 15 | import sentry_flutter 16 | import shared_preferences_foundation 17 | import sqflite_darwin 18 | import url_launcher_macos 19 | 20 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 21 | AwesomeNotificationsPlugin.register(with: registry.registrar(forPlugin: "AwesomeNotificationsPlugin")) 22 | FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) 23 | FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) 24 | LocalNotifierPlugin.register(with: registry.registrar(forPlugin: "LocalNotifierPlugin")) 25 | FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) 26 | PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin")) 27 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 28 | SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin")) 29 | SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) 30 | SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) 31 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 32 | } 33 | -------------------------------------------------------------------------------- /macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.14' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | target 'RunnerTests' do 35 | inherit! :search_paths 36 | end 37 | end 38 | 39 | post_install do |installer| 40 | installer.pods_project.targets.each do |target| 41 | flutter_additional_macos_build_settings(target) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @main 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = blt 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.apps.blt 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2024 com.apps. All rights reserved. 15 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | com.apple.security.network.client 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.network.client 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /macos/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: blt 2 | description: The BLT-Flutter App 3 | 4 | version: 1.0.8+1 5 | publish_to: none 6 | 7 | environment: 8 | sdk: ">=3.0.0 <4.0.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | flutter_markdown: ^0.7.1 14 | google_fonts: ">=3.0.1 <5.0.0" 15 | http: ^1.1.0 16 | image_picker: ^1.1.1 17 | receive_sharing_intent: 18 | git: 19 | url: https://github.com/Thogsit/receive_sharing_intent 20 | shared_preferences: ^2.0.5 21 | flutter_svg: ">=1.0.3 <3.0.0" 22 | flutter_riverpod: ^1.0.3 23 | intl: 24 | flutter_secure_storage: ^9.0.0 25 | smooth_page_indicator: ^1.0.0+2 26 | pasteboard: ^0.2.0 27 | path_provider: ^2.0.13 28 | url_launcher: ^6.2.5 29 | #flutter_inappwebview: ^5.7.2+3 30 | font_awesome_flutter: ^10.4.0 31 | sentry_flutter: ^8.2.0 32 | cached_network_image: ^3.2.3 33 | flutter_localizations: 34 | sdk: flutter 35 | primer_progress_bar: ^0.4.2 36 | testing: ^0.0.11 37 | lottie: ^3.1.2 38 | webview_flutter: ^3.0.4 39 | permission_handler: ^11.3.1 40 | awesome_notifications: ^0.9.3+1 41 | local_notifier: ^0.1.6 42 | sqflite: ^2.4.1 43 | 44 | dev_dependencies: 45 | flutter_launcher_icons: ">=0.9.0 <0.13.0" 46 | flutter_test: 47 | sdk: flutter 48 | 49 | flutter: 50 | generate: true 51 | uses-material-design: true 52 | assets: 53 | - assets/ 54 | - assets/login_signup/ 55 | 56 | flutter_icons: 57 | android: "ic_launcher" 58 | ios: true 59 | image_path: "assets/app_large_icon.png" 60 | remove_alpha_ios: true 61 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set PRODUCT_BUNDLE_IDENTIFIER="${PRODUCT_BUNDLE_IDENTIFIER:=com.apps.blt}" 3 | set BASE_URL="${BASE_URL:=www.owasp.org/BLT/}" 4 | set SENTRY_DSN="${SENTRY_DSN:=https://example-234234324.com/4504877879197696}" 5 | 6 | sed -i.backup "s~www.owasp.org/BLT/~$BASE_URL~g" lib/src/util/endpoints/general_endpoints.dart 7 | echo "sed BASE_URL" 8 | 9 | sed -i.backup "s~https://example-234234324.com/4504877879197696~$SENTRY_DSN~g" lib/main.dart 10 | echo "sed SENTRY_DSN" 11 | 12 | sed -i.backup "s/com.apps.blt/$PRODUCT_BUNDLE_IDENTIFIER/g" ios/Runner.xcodeproj/project.pbxproj 13 | echo "sed PRODUCT_BUNDLE_IDENTIFIER_1" 14 | 15 | sed -i.backup "s/com.apps.blt/$PRODUCT_BUNDLE_IDENTIFIER/g" android/app/build.gradle 16 | echo "sed PRODUCT_BUNDLE_IDENTIFIER_2" 17 | 18 | sed -i.backup "s/com.apps.blt/$PRODUCT_BUNDLE_IDENTIFIER/g" android/app/src/main/AndroidManifest.xml 19 | echo "sed PRODUCT_BUNDLE_IDENTIFIER_3" 20 | -------------------------------------------------------------------------------- /test/integration_tests/issue_card_test.dart: -------------------------------------------------------------------------------- 1 | import '../test_imports.dart'; 2 | 3 | void main() { 4 | testWidgets("Issue Card Test", (WidgetTester tester) async { 5 | final mockIssue = Issue( 6 | id: 1, 7 | url: 'http://bugheist.com', 8 | title: 'Issue 1', 9 | description: '', 10 | label: 0, 11 | userAgent: 'Mozilla/5.0 (X11; Linux x86_64', 12 | created: DateTime.now(), 13 | domain: 3, 14 | isOpen: true, 15 | screenshotsLink: [], 16 | likes: 0, 17 | isVerified: false, 18 | ); 19 | 20 | await tester.pumpWidget( 21 | MaterialApp( 22 | home: Scaffold( 23 | body: SizedBox( 24 | height: 1900, 25 | width: 600, 26 | child: Padding( 27 | padding: const EdgeInsets.all(18.0).copyWith(bottom: 0), 28 | child: IssueCard( 29 | issue: mockIssue, 30 | isTesting: true, 31 | ), 32 | ), 33 | ), 34 | ), 35 | ), 36 | ); 37 | 38 | await tester.pumpAndSettle(); 39 | 40 | expect(find.byType(Card), findsOneWidget); 41 | expect(find.byType(Image), findsOneWidget); 42 | // cant integrate this to the test because additional apis are being called using http here. 43 | // expect(find.byType(IssueLikeButton), findsOneWidget); 44 | }); 45 | } 46 | -------------------------------------------------------------------------------- /test/integration_tests/show_company_test.dart: -------------------------------------------------------------------------------- 1 | import '../test_imports.dart'; 2 | 3 | void main() { 4 | testWidgets("Company List Test", (WidgetTester tester) async { 5 | final mockcompanyList = [ 6 | Company( 7 | 1, 8 | "Company 1", 9 | "fhkldjshfklhasfk", 10 | "company@1234.com", 11 | "company1.com", 12 | "black", 13 | 2, 14 | 1, 15 | 3, 16 | DateTime.now(), 17 | "kshdfkasl", 18 | "tester", 19 | "", 20 | "", 21 | true, 22 | ), 23 | Company( 24 | 2, 25 | "Company 2", 26 | "sakldfklhasfk", 27 | "test@1234.com", 28 | "tses.com", 29 | "blue", 30 | 1, 31 | 5, 32 | 6, 33 | DateTime.now(), 34 | "fdsdfsd", 35 | "test", 36 | "", 37 | "", 38 | true, 39 | ) 40 | ]; 41 | 42 | await tester.pumpWidget(MaterialApp( 43 | home: Scaffold( 44 | body: ShowCompanyList( 45 | isTest: true, 46 | companyList: mockcompanyList, 47 | ), 48 | ), 49 | )); 50 | await tester.pumpAndSettle(); 51 | 52 | expect(find.byType(ListView), findsOneWidget); 53 | expect(find.byType(ListTile), findsNWidgets(mockcompanyList.length)); 54 | 55 | for (var company in mockcompanyList) { 56 | expect(find.text(company.companyName), findsOneWidget); 57 | } 58 | }); 59 | } 60 | -------------------------------------------------------------------------------- /test/integration_tests/show_issues_test.dart: -------------------------------------------------------------------------------- 1 | import '../test_imports.dart'; 2 | 3 | void main() { 4 | testWidgets("Issue List Test", (WidgetTester tester) async { 5 | final mockIssueList = [ 6 | Issue( 7 | id: 1, 8 | url: 'http://bugheist.com', 9 | title: 'Issue 1', 10 | description: '', 11 | label: 0, 12 | userAgent: 'Mozilla/5.0 (X11; Linux x86_64', 13 | created: DateTime.now(), 14 | domain: 3, 15 | isOpen: true, 16 | screenshotsLink: [], 17 | isVerified: false, 18 | ), 19 | Issue( 20 | id: 2, 21 | url: 'http://test.com', 22 | title: 'Issue 2', 23 | created: DateTime.now(), 24 | description: '## Hello there', 25 | userAgent: 'Mozilla/5.0 (X11; Linux x86_64', 26 | domain: 1, 27 | screenshotsLink: [], 28 | isVerified: true, 29 | isOpen: false, 30 | ), 31 | ]; 32 | 33 | await tester.pumpWidget(MaterialApp( 34 | home: Scaffold( 35 | body: ShowIssueList(isTesting: true, issueList: mockIssueList), 36 | ), 37 | )); 38 | 39 | await tester.pumpAndSettle(); 40 | 41 | expect(find.byType(ListView), findsOneWidget); 42 | expect(find.byType(ListTile), findsNWidgets(mockIssueList.length)); 43 | 44 | for (var issue in mockIssueList) { 45 | expect(find.text(issue.title), findsOneWidget); 46 | } 47 | }); 48 | } 49 | -------------------------------------------------------------------------------- /test/test_imports.dart: -------------------------------------------------------------------------------- 1 | export 'dart:convert'; 2 | export 'package:blt/src/components/components_import.dart'; 3 | export 'package:blt/src/models/user_model.dart'; 4 | export 'package:flutter_test/flutter_test.dart'; 5 | export 'package:http/testing.dart'; 6 | export 'package:blt/src/pages/leaderboards/leaderboards_imports.dart'; 7 | export 'package:blt/src/util/api/user_api.dart'; 8 | export 'package:blt/src/pages/home/issues.dart'; 9 | export 'package:flutter/material.dart'; 10 | export 'package:blt/src/models/company_model.dart'; 11 | export 'package:blt/src/pages/companies/company_list_page.dart'; 12 | -------------------------------------------------------------------------------- /test/unit_tests/project_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:blt/src/util/api/project_apis.dart'; 2 | import 'package:http/http.dart' as http; 3 | import '../test_imports.dart'; 4 | 5 | void main() { 6 | group("Project Api's Test", () { 7 | test("get all projects", () async { 8 | final dynamic mockResponse = { 9 | "count": 1, 10 | "projects": [ 11 | { 12 | "id": 13, 13 | "name": "TestProject", 14 | "slug": "testproject", 15 | "description": "Test Project", 16 | "github_url": "https://github.com/Test/test", 17 | "wiki_url": "", 18 | "homepage_url": "", 19 | "logo_url": "https://test.org/www-test-test/test/test/test.png", 20 | "created": "2024-07-16T19:08:44.846535Z", 21 | "modified": "2024-08-02T14:53:41.131125Z", 22 | "contributors": [ 23 | { 24 | "id": 00, 25 | "name": "cont1", 26 | "github_id": 000111, 27 | "github_url": "https://github.com/cont1", 28 | "avatar_url": "https://avatars.githubusercontent.com/u/cont1", 29 | "contributor_type": "User", 30 | "contributions": 2, 31 | "created": "2024-08-04T19:03:52.956106Z" 32 | }, 33 | { 34 | "id": 01, 35 | "name": "bot[bot]", 36 | "github_id": 002200, 37 | "github_url": "https://github.com/BOT/bot", 38 | "avatar_url": "https://avatars.githubusercontent.com/in/bot", 39 | "contributor_type": "Bot", 40 | "contributions": 1, 41 | "created": "2024-08-04T19:03:52.956106Z" 42 | }, 43 | ] 44 | } 45 | ] 46 | }; 47 | final client = MockClient((request) async { 48 | final response = mockResponse; 49 | return http.Response(jsonEncode(response), 200); 50 | }); 51 | final result = await ProjectAPiClient.getAllProjects(testClient: client); 52 | expect(result?.length, 1); 53 | expect(result?[0].contributors?.length, 2); 54 | expect(result?[0].name, 'TestProject'); 55 | expect(result?[0].contributors?[0].name, "cont1"); 56 | expect(result?[0].contributors?[0].contributions, 2); 57 | expect(result?[0].contributors?[1].name, "bot[bot]"); 58 | expect(result?[0].contributors?[1].contributions, 1); 59 | }); 60 | }); 61 | } 62 | -------------------------------------------------------------------------------- /test/unit_tests/user_test.dart: -------------------------------------------------------------------------------- 1 | import '../test_imports.dart'; 2 | import 'package:http/http.dart' as http; 3 | 4 | void main() { 5 | setUp(() { 6 | currentUser = guestUser; 7 | }); 8 | group("User Api's Test", () { 9 | test('Get User Info', () async { 10 | // Mock response data 11 | final dynamic mockResponse = { 12 | 'count': 1, 13 | "results": [ 14 | { 15 | 'username': 'test_user', 16 | 'token': 'test_token', 17 | 'other_data': 'test_data', 18 | 'description': 'description', 19 | 'email': 'test@gmail.com', 20 | } 21 | ] 22 | }; 23 | 24 | final user = User(); 25 | user.id = 1; 26 | user.username = 'test_user'; 27 | user.token = 'test_token'; 28 | 29 | final client = MockClient((request) async { 30 | if (request.headers['Authorization'] == 'Token test_token') { 31 | return http.Response(jsonEncode(mockResponse), 200); 32 | } else { 33 | return http.Response('Unauthorized', 401); 34 | } 35 | }); 36 | 37 | final responseUser = await UserApiClient.getUserInfo(client, user); 38 | expect(responseUser?.username, 'test_user'); 39 | expect(responseUser?.description, 'description'); 40 | expect(responseUser?.email, 'test@gmail.com'); 41 | expect(responseUser?.token, 'test_token'); 42 | }); 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | void RegisterPlugins(flutter::PluginRegistry* registry) { 19 | AwesomeNotificationsPluginCApiRegisterWithRegistrar( 20 | registry->GetRegistrarForPlugin("AwesomeNotificationsPluginCApi")); 21 | FileSelectorWindowsRegisterWithRegistrar( 22 | registry->GetRegistrarForPlugin("FileSelectorWindows")); 23 | FlutterSecureStorageWindowsPluginRegisterWithRegistrar( 24 | registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); 25 | LocalNotifierPluginRegisterWithRegistrar( 26 | registry->GetRegistrarForPlugin("LocalNotifierPlugin")); 27 | PasteboardPluginRegisterWithRegistrar( 28 | registry->GetRegistrarForPlugin("PasteboardPlugin")); 29 | PermissionHandlerWindowsPluginRegisterWithRegistrar( 30 | registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); 31 | SentryFlutterPluginRegisterWithRegistrar( 32 | registry->GetRegistrarForPlugin("SentryFlutterPlugin")); 33 | UrlLauncherWindowsRegisterWithRegistrar( 34 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 35 | } 36 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | awesome_notifications 7 | file_selector_windows 8 | flutter_secure_storage_windows 9 | local_notifier 10 | pasteboard 11 | permission_handler_windows 12 | sentry_flutter 13 | url_launcher_windows 14 | ) 15 | 16 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 17 | ) 18 | 19 | set(PLUGIN_BUNDLED_LIBRARIES) 20 | 21 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 22 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 23 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 25 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 26 | endforeach(plugin) 27 | 28 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 29 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 30 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 31 | endforeach(ffi_plugin) 32 | -------------------------------------------------------------------------------- /windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} WIN32 10 | "flutter_window.cpp" 11 | "main.cpp" 12 | "utils.cpp" 13 | "win32_window.cpp" 14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 15 | "Runner.rc" 16 | "runner.exe.manifest" 17 | ) 18 | 19 | # Apply the standard set of build settings. This can be removed for applications 20 | # that need different build settings. 21 | apply_standard_settings(${BINARY_NAME}) 22 | 23 | # Add preprocessor definitions for the build version. 24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 29 | 30 | # Disable Windows macros that collide with C++ standard library functions. 31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 32 | 33 | # Add dependency libraries and include directories. Add any application-specific 34 | # dependencies here. 35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 36 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") 37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 38 | 39 | # Run the Flutter tool portions of the build. This must not be removed. 40 | add_dependencies(${BINARY_NAME} flutter_assemble) 41 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | 30 | flutter_controller_->engine()->SetNextFrameCallback([&]() { 31 | this->Show(); 32 | }); 33 | 34 | // Flutter can complete the first frame before the "show window" callback is 35 | // registered. The following call ensures a frame is pending to ensure the 36 | // window is shown. It is a no-op if the first frame hasn't completed yet. 37 | flutter_controller_->ForceRedraw(); 38 | 39 | return true; 40 | } 41 | 42 | void FlutterWindow::OnDestroy() { 43 | if (flutter_controller_) { 44 | flutter_controller_ = nullptr; 45 | } 46 | 47 | Win32Window::OnDestroy(); 48 | } 49 | 50 | LRESULT 51 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 52 | WPARAM const wparam, 53 | LPARAM const lparam) noexcept { 54 | // Give Flutter, including plugins, an opportunity to handle window messages. 55 | if (flutter_controller_) { 56 | std::optional result = 57 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 58 | lparam); 59 | if (result) { 60 | return *result; 61 | } 62 | } 63 | 64 | switch (message) { 65 | case WM_FONTCHANGE: 66 | flutter_controller_->engine()->ReloadSystemFonts(); 67 | break; 68 | } 69 | 70 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 71 | } 72 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(10, 10); 29 | Win32Window::Size size(1280, 720); 30 | if (!window.Create(L"blt_flutter", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | window.SetQuitOnClose(true); 34 | 35 | ::MSG msg; 36 | while (::GetMessage(&msg, nullptr, 0, 0)) { 37 | ::TranslateMessage(&msg); 38 | ::DispatchMessage(&msg); 39 | } 40 | 41 | ::CoUninitialize(); 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OWASP-BLT/BLT-Flutter/c4b6ed0f33958ef2024738e6b1c8716429cbbf00/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | unsigned int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr) 51 | -1; // remove the trailing null character 52 | int input_length = (int)wcslen(utf16_string); 53 | std::string utf8_string; 54 | if (target_length == 0 || target_length > utf8_string.max_size()) { 55 | return utf8_string; 56 | } 57 | utf8_string.resize(target_length); 58 | int converted_length = ::WideCharToMultiByte( 59 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 60 | input_length, utf8_string.data(), target_length, nullptr, nullptr); 61 | if (converted_length == 0) { 62 | return std::string(); 63 | } 64 | return utf8_string; 65 | } 66 | -------------------------------------------------------------------------------- /windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | --------------------------------------------------------------------------------