├── env_example.txt ├── web ├── favicon.ico ├── favicon-16x16.png ├── favicon-32x32.png ├── icons │ ├── icon-192.png │ ├── icon-384.png │ ├── apple-touch-icon.png │ ├── mstile-150x150.png │ ├── icon-maskable-192.png │ ├── icon-maskable-512.png │ └── safari-pinned-tab.svg ├── manifest.json ├── github_login.js └── index.html ├── assets ├── images │ ├── events.jpg │ ├── teams.jpg │ ├── welcome.jpg │ ├── fork_icon.png │ ├── handshake.png │ ├── ocy_logo.png │ ├── add_skills.png │ ├── github_logo.png │ ├── google_logo.png │ └── icon_community.png └── fonts │ ├── PublicSans_Bold.otf │ ├── PublicSans_Regular.otf │ └── PublicSans_ExtraBold.otf ├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── values-night │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── ocy │ │ │ │ │ └── ocyclient │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle └── build.gradle ├── lib ├── external │ └── github_sign_in │ │ └── lib │ │ ├── github_sign_in.dart │ │ └── src │ │ ├── github_sign_in_result.dart │ │ ├── github_sign_in_page.dart │ │ └── github_sign_in.dart ├── models │ ├── localization │ │ └── language.dart │ ├── user │ │ └── user_model.dart │ ├── team │ │ └── team_model.dart │ └── project │ │ └── project_model.dart ├── blocs │ ├── profile_bloc.dart │ ├── edit_profile_bloc.dart │ ├── community_bloc.dart │ ├── navigation_bloc.dart │ ├── teams_bloc.dart │ ├── projects_bloc.dart │ └── locale_bloc.dart ├── widgets │ ├── Utils │ │ ├── snackbar.dart │ │ ├── measure_size_render_object.dart │ │ ├── scroll_animation.dart │ │ ├── common_widgets.dart │ │ ├── custom_inputfields.dart │ │ └── navigation_drawer.dart │ ├── Milestones │ │ └── milestones.dart │ ├── Community │ │ └── community.dart │ ├── ComingSoon │ │ └── coming_soon.dart │ ├── Home │ │ ├── home.dart │ │ └── sub_pages │ │ │ ├── events.dart │ │ │ ├── intro.dart │ │ │ ├── footer.dart │ │ │ └── benefits.dart │ ├── Auth │ │ ├── page_view │ │ │ └── login_intro_page.dart │ │ └── login_signup.dart │ ├── Teams │ │ ├── member │ │ │ ├── member_horizontal.dart │ │ │ └── member_vertical.dart │ │ ├── team_card.dart │ │ └── teams.dart │ └── Profile │ │ ├── widgets │ │ └── accounts.dart │ │ ├── edit_profile.dart │ │ └── profile.dart ├── utils │ └── app_translations.dart ├── configs │ └── config.dart └── main.dart ├── attribution.md ├── firebase.json ├── dartdoc_options.yaml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── analysis_options.yaml ├── .metadata ├── data └── teams.json ├── pubspec.yaml ├── .firebase └── hosting.YnVpbGRcd2Vi.cache ├── CODE_OF_CONDUCT.md └── README.md /env_example.txt: -------------------------------------------------------------------------------- 1 | github_access_token = 'YOUR_TOKEN_HERE' -------------------------------------------------------------------------------- /web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/web/favicon.ico -------------------------------------------------------------------------------- /web/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/web/favicon-16x16.png -------------------------------------------------------------------------------- /web/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/web/favicon-32x32.png -------------------------------------------------------------------------------- /web/icons/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/web/icons/icon-192.png -------------------------------------------------------------------------------- /web/icons/icon-384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/web/icons/icon-384.png -------------------------------------------------------------------------------- /assets/images/events.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/assets/images/events.jpg -------------------------------------------------------------------------------- /assets/images/teams.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/assets/images/teams.jpg -------------------------------------------------------------------------------- /assets/images/welcome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/assets/images/welcome.jpg -------------------------------------------------------------------------------- /assets/images/fork_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/assets/images/fork_icon.png -------------------------------------------------------------------------------- /assets/images/handshake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/assets/images/handshake.png -------------------------------------------------------------------------------- /assets/images/ocy_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/assets/images/ocy_logo.png -------------------------------------------------------------------------------- /assets/images/add_skills.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/assets/images/add_skills.png -------------------------------------------------------------------------------- /assets/images/github_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/assets/images/github_logo.png -------------------------------------------------------------------------------- /assets/images/google_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/assets/images/google_logo.png -------------------------------------------------------------------------------- /web/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/web/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /web/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/web/icons/mstile-150x150.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /assets/fonts/PublicSans_Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/assets/fonts/PublicSans_Bold.otf -------------------------------------------------------------------------------- /assets/images/icon_community.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/assets/images/icon_community.png -------------------------------------------------------------------------------- /web/icons/icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/web/icons/icon-maskable-192.png -------------------------------------------------------------------------------- /web/icons/icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/web/icons/icon-maskable-512.png -------------------------------------------------------------------------------- /assets/fonts/PublicSans_Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/assets/fonts/PublicSans_Regular.otf -------------------------------------------------------------------------------- /assets/fonts/PublicSans_ExtraBold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/assets/fonts/PublicSans_ExtraBold.otf -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCodeyard/ocyclient/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /lib/external/github_sign_in/lib/github_sign_in.dart: -------------------------------------------------------------------------------- 1 | library github_sign_in; 2 | 3 | export 'src/github_sign_in.dart'; 4 | export 'src/github_sign_in_result.dart'; 5 | -------------------------------------------------------------------------------- /attribution.md: -------------------------------------------------------------------------------- 1 |
Icons made by Freepik from www.flaticon.com
2 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/ocy/ocyclient/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.ocy.ocyclient 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /lib/models/localization/language.dart: -------------------------------------------------------------------------------- 1 | class Language { 2 | final String name; 3 | final String countryCode; 4 | final String languageCode; 5 | 6 | Language(this.name, this.countryCode, this.languageCode); 7 | } 8 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 7 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build/web", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/blocs/profile_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// {@category Blocs} 4 | class ProfileBloc extends ChangeNotifier { 5 | int _currentSelectedMenuItem = 0; 6 | 7 | int get currentSelectedMenuItem => _currentSelectedMenuItem; 8 | 9 | void setCurrentSelectedItem(int index) { 10 | _currentSelectedMenuItem = index; 11 | notifyListeners(); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /lib/blocs/edit_profile_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// {@category Blocs} 4 | class EditProfileBloc extends ChangeNotifier { 5 | int _currentSelectedMenuItem = 0; 6 | 7 | int get currentSelectedMenuItem => _currentSelectedMenuItem; 8 | 9 | void setCurrentSelectedItem(int index) { 10 | _currentSelectedMenuItem = index; 11 | notifyListeners(); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /lib/blocs/community_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// {@category Blocs} 4 | class CommunityBloc extends ChangeNotifier { 5 | bool _hasCompletedCurtainAnimation = false; 6 | 7 | bool get hasCompletedCurtainAnimation => _hasCompletedCurtainAnimation; 8 | 9 | void setCurtainAnimationStatus() { 10 | _hasCompletedCurtainAnimation = true; 11 | notifyListeners(); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/widgets/Utils/snackbar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fluttertoast/fluttertoast.dart'; 3 | 4 | showToast(String text) { 5 | Fluttertoast.showToast( 6 | msg: text, 7 | toastLength: Toast.LENGTH_SHORT, 8 | gravity: ToastGravity.BOTTOM_RIGHT, 9 | timeInSecForIosWeb: 2, 10 | webShowClose: true, 11 | webBgColor: "linear-gradient(60deg, #647DEE 12%, #7F53AC 100%)", 12 | webPosition: "left", 13 | textColor: Colors.white, 14 | fontSize: 16.0, 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /dartdoc_options.yaml: -------------------------------------------------------------------------------- 1 | dartdoc: 2 | categories: 3 | "Blocs": 4 | markdown: README.md 5 | name: Blocs 6 | "Configs": 7 | markdown: README.md 8 | name: Configs 9 | "Models": 10 | markdown: README.md 11 | name: Models 12 | "External": 13 | markdown: README.md 14 | name: External 15 | "Widgets": 16 | markdown: README.md 17 | name: Widgets 18 | categoryOrder: [ "Blocs","Widgets","Models","External" ] 19 | favicon: web/favicon.ico 20 | showUndocumentedCategories: true -------------------------------------------------------------------------------- /lib/external/github_sign_in/lib/src/github_sign_in_result.dart: -------------------------------------------------------------------------------- 1 | class GitHubSignInResult { 2 | final String? token; 3 | final GitHubSignInResultStatus status; 4 | final String errorMessage; 5 | 6 | GitHubSignInResult( 7 | this.status, { 8 | this.token, 9 | this.errorMessage = "", 10 | }); 11 | } 12 | 13 | enum GitHubSignInResultStatus { 14 | /// The login was successful. 15 | ok, 16 | 17 | /// The user cancelled the login flow, usually by closing the 18 | /// login dialog. 19 | cancelled, 20 | 21 | /// The login completed with an error and the user couldn't log 22 | /// in for some reason. 23 | failed, 24 | } 25 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /lib/utils/app_translations.dart: -------------------------------------------------------------------------------- 1 | import 'package:get/get.dart'; 2 | 3 | class AppTranslations extends Translations { 4 | @override 5 | Map> get keys => { 6 | 'en_US': { 7 | "home": "Home", 8 | "about_us": "About Us", 9 | "teams": "Teams", 10 | }, 11 | 'bn_IN': { 12 | "home": "ঘর", 13 | "about_us": "আমাদের সম্পর্কে", 14 | "teams": "দল", 15 | }, 16 | 'hn_IN': { 17 | "home": "घर", 18 | "about_us": "हमारे बारे में", 19 | "teams": "दल", 20 | }, 21 | 'mt_IN':{ 22 | "home":"मुख्यपृष्ठ", 23 | "about_us":"आमच्या बद्दल", 24 | "teams":"संघ" 25 | } 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /lib/blocs/navigation_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:get/get_navigation/src/extension_navigation.dart'; 3 | import 'package:get/utils.dart'; 4 | 5 | /// {@category Blocs} 6 | class NavigationBloc extends ChangeNotifier { 7 | late GlobalKey _navigatorKey; 8 | 9 | GlobalKey get navigatorKey => _navigatorKey; 10 | 11 | NavigationBloc(GlobalKey navigatorKey) { 12 | _navigatorKey = navigatorKey; 13 | } 14 | 15 | void toRoute(String s, 16 | {bool shouldPopCurrent = false, bool shouldPopAll = false}) { 17 | if (shouldPopAll) { 18 | Get.offAllNamed(s); 19 | } else if (shouldPopCurrent) { 20 | Get.offAndToNamed(s); 21 | } else { 22 | Get.toNamed(s); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/widgets/Milestones/milestones.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:get/get.dart'; 4 | import 'package:ocyclient/widgets/ComingSoon/coming_soon.dart'; 5 | import 'package:ocyclient/widgets/Utils/ocy_scaffold.dart'; 6 | 7 | class MilestonesPage extends StatefulWidget { 8 | const MilestonesPage({Key? key}) : super(key: key); 9 | 10 | @override 11 | State createState() => _MilestonesPageState(); 12 | } 13 | 14 | class _MilestonesPageState extends State { 15 | 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | SystemChrome.setApplicationSwitcherDescription( 20 | ApplicationSwitcherDescription( 21 | label: 'Milestones 🏆', 22 | primaryColor: Theme.of(context).primaryColor.value, 23 | ), 24 | ); 25 | 26 | return const ComingSoon(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | 36 | # Symbolication related 37 | app.*.symbols 38 | 39 | # Obfuscation related 40 | app.*.map.json 41 | 42 | # Android Studio will place build artifacts here 43 | /android/app/debug 44 | /android/app/profile 45 | /android/app/release 46 | 47 | env 48 | lib/firebase_options.dart 49 | android/app/google-services.json 50 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, 4 | email, or any other method with the owners of this repository before making a change. 5 | 6 | Please note we have a code of conduct, please follow it in all your interactions with the project. 7 | 8 | ## Pull Request Process 9 | 10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a 11 | build. 12 | 2. Update the README.md with details of changes to the interface, this includes new environment 13 | variables, exposed ports, useful file locations and container parameters. 14 | 3. Increase the version numbers in any examples files and the README.md to the new version that this 15 | Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). 16 | 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you 17 | do not have permission to do that, you may request the second reviewer to merge it for you. 18 | -------------------------------------------------------------------------------- /lib/widgets/Community/community.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:ocyclient/blocs/community_bloc.dart'; 4 | import 'package:ocyclient/widgets/ComingSoon/coming_soon.dart'; 5 | import 'package:ocyclient/widgets/Utils/ocy_scaffold.dart'; 6 | import 'package:provider/provider.dart'; 7 | 8 | class CommunityPage extends StatefulWidget { 9 | const CommunityPage({Key? key}) : super(key: key); 10 | 11 | @override 12 | State createState() => _CommunityPageState(); 13 | } 14 | 15 | class _CommunityPageState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | SystemChrome.setApplicationSwitcherDescription( 19 | ApplicationSwitcherDescription( 20 | label: 'Community 🤝', 21 | primaryColor: Theme.of(context).primaryColor.value, 22 | ), 23 | ); 24 | 25 | Size size = MediaQuery.of(context).size; 26 | CommunityBloc cb = Provider.of(context); 27 | return const ComingSoon(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Open Codeyard", 3 | "short_name": "OCY", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "Official client side application of Open Codeyard", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-384.png", 19 | "sizes": "384x384", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /lib/widgets/Utils/measure_size_render_object.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/rendering.dart'; 3 | 4 | typedef OnWidgetSizeChange = void Function(Size size); 5 | 6 | class MeasureSizeRenderObject extends RenderProxyBox { 7 | Size? oldSize; 8 | final OnWidgetSizeChange onChange; 9 | 10 | MeasureSizeRenderObject(this.onChange); 11 | 12 | @override 13 | void performLayout() { 14 | super.performLayout(); 15 | 16 | Size? newSize = child?.size; 17 | if (oldSize == newSize) return; 18 | 19 | oldSize = newSize; 20 | WidgetsBinding.instance.addPostFrameCallback((_) { 21 | onChange(newSize!); 22 | }); 23 | } 24 | } 25 | 26 | class MeasureSize extends SingleChildRenderObjectWidget { 27 | final OnWidgetSizeChange onChange; 28 | 29 | const MeasureSize({ 30 | Key? key, 31 | required this.onChange, 32 | required Widget child, 33 | }) : super(key: key, child: child); 34 | 35 | @override 36 | RenderObject createRenderObject(BuildContext context) { 37 | return MeasureSizeRenderObject(onChange); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Open Codeyard 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/models/user/user_model.dart: -------------------------------------------------------------------------------- 1 | class UserModel { 2 | String uid; 3 | String email; 4 | String name; 5 | String profilePicUrl; 6 | String userGitHubAccessToken; 7 | List loginProvidersConnected = []; 8 | Map skills = {}; 9 | String? bio; 10 | String? phoneNumber; 11 | String? dob; 12 | String? gender; 13 | String? employmentStatus; 14 | String? locality; 15 | 16 | UserModel( 17 | this.uid, 18 | this.email, 19 | this.name, 20 | this.profilePicUrl, 21 | this.userGitHubAccessToken, 22 | this.skills, 23 | this.loginProvidersConnected, { 24 | this.bio, 25 | this.phoneNumber, 26 | this.dob, 27 | this.gender, 28 | this.employmentStatus, 29 | this.locality, 30 | }); 31 | 32 | @override 33 | String toString() { 34 | return 'UserModel{uid: $uid, email: $email, name: $name, profilePicUrl: $profilePicUrl, userGitHubAccessToken: $userGitHubAccessToken, loginProvidersConnected: $loginProvidersConnected, skills: $skills, bio: $bio, phoneNumber: $phoneNumber, dob: $dob, gender: $gender, employmentStatus: $employmentStatus, locality: $locality}'; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/models/team/team_model.dart: -------------------------------------------------------------------------------- 1 | class Team { 2 | String id; 3 | String name; 4 | List members; 5 | 6 | // from json 7 | Team({ 8 | required this.id, 9 | required this.name, 10 | required this.members, 11 | }); 12 | 13 | static fromJson(json) { 14 | return Team( 15 | id: json["id"], 16 | name: json["name"], 17 | members: List.from(json["members"] 18 | .map( 19 | (json) => Member.fromJson(json), 20 | ) 21 | .toList()), 22 | ); 23 | } 24 | } 25 | 26 | class Member { 27 | String name; 28 | String title; 29 | String image; 30 | String? github; 31 | String? linkedIn; 32 | String? twitter; 33 | 34 | Member({ 35 | required this.name, 36 | required this.title, 37 | required this.image, 38 | this.github, 39 | this.linkedIn, 40 | this.twitter, 41 | }); 42 | 43 | static fromJson(json) { 44 | return Member( 45 | name: json["name"], 46 | image: json["image"], 47 | title: json["title"], 48 | github: json["github"], 49 | linkedIn: json["linkedIn"], 50 | twitter: json["twitter"], 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/models/project/project_model.dart: -------------------------------------------------------------------------------- 1 | class ProjectModel { 2 | String name; 3 | String id; 4 | DateTime creationDate; 5 | String description; 6 | List contributors = []; 7 | String repoUrl; 8 | int starCount, watchCount, activeIssuesCount, forkCount; 9 | 10 | setContributors(List urls) { 11 | contributors = urls; 12 | } 13 | 14 | ProjectModel({ 15 | required this.name, 16 | required this.id, 17 | required this.creationDate, 18 | required this.description, 19 | required this.repoUrl, 20 | required this.starCount, 21 | required this.watchCount, 22 | required this.activeIssuesCount, 23 | required this.forkCount, 24 | }); 25 | 26 | factory ProjectModel.fromJson(Map parsedJson) { 27 | return ProjectModel( 28 | id: parsedJson['id'].toString(), 29 | name: parsedJson['name'].toString(), 30 | creationDate: DateTime.parse(parsedJson['created_at'].toString()), 31 | description: parsedJson['description'].toString(), 32 | repoUrl: parsedJson['html_url'].toString(), 33 | activeIssuesCount: parsedJson['open_issues_count'], 34 | starCount: parsedJson['stargazers_count'], 35 | watchCount: parsedJson['watchers_count'], 36 | forkCount: parsedJson['forks_count'], 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/widgets/ComingSoon/coming_soon.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ocyclient/widgets/Utils/ocy_scaffold.dart'; 3 | 4 | class ComingSoon extends StatelessWidget { 5 | const ComingSoon({Key? key}) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | Size size = MediaQuery.of(context).size; 10 | 11 | return OcyScaffold( 12 | body: SizedBox( 13 | width: size.width, 14 | child: Column( 15 | crossAxisAlignment: CrossAxisAlignment.center, 16 | mainAxisAlignment: MainAxisAlignment.center, 17 | mainAxisSize: MainAxisSize.max, 18 | children: [ 19 | ClipRRect( 20 | borderRadius: BorderRadius.circular(15.0), 21 | child: FadeInImage.assetNetwork( 22 | placeholder: "assets/images/ocy_logo.png", 23 | fadeInCurve: Curves.easeOutQuint, 24 | image: "https://i.imgur.com/mxc0F3W.gif", 25 | width: 200, 26 | height: 200, 27 | ), 28 | ), 29 | const SizedBox(height: 50,), 30 | const Text( 31 | "Coming Soon!", 32 | style: TextStyle( 33 | fontWeight: FontWeight.w700, 34 | fontFamily: "PublicSans", 35 | fontSize: 35, 36 | ), 37 | ), 38 | ], 39 | ), 40 | ), 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /lib/widgets/Home/home.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:ocyclient/widgets/Home/sub_pages/benefits.dart'; 4 | import 'package:ocyclient/widgets/Home/sub_pages/events.dart'; 5 | import 'package:ocyclient/widgets/Home/sub_pages/footer.dart'; 6 | import 'package:ocyclient/widgets/Home/sub_pages/intro.dart'; 7 | import 'package:ocyclient/widgets/Home/sub_pages/projects.dart'; 8 | import 'package:ocyclient/widgets/Utils/ocy_scaffold.dart'; 9 | 10 | class HomePage extends StatefulWidget { 11 | const HomePage({Key? key}) : super(key: key); 12 | 13 | @override 14 | State createState() => _HomePageState(); 15 | } 16 | 17 | class _HomePageState extends State { 18 | @override 19 | Widget build(BuildContext context) { 20 | SystemChrome.setApplicationSwitcherDescription( 21 | ApplicationSwitcherDescription( 22 | label: 'Home 🏠', 23 | primaryColor: Theme.of(context).primaryColor.value, 24 | ), 25 | ); 26 | 27 | //Add attribution 28 | //Community icon by Icons8 29 | 30 | return OcyScaffold( 31 | body: SingleChildScrollView( 32 | physics: const BouncingScrollPhysics(), 33 | child: Column( 34 | crossAxisAlignment: CrossAxisAlignment.center, 35 | children: const [ 36 | Intro(), 37 | // if (kDebugMode) UpcomingEvents(), 38 | Benefits(), 39 | Projects(), 40 | Footer(), 41 | ], 42 | ), 43 | ), 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /.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: f1875d570e39de09040c8f79aa13cc56baab8db1 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: f1875d570e39de09040c8f79aa13cc56baab8db1 17 | base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 18 | - platform: android 19 | create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 20 | base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 21 | - platform: ios 22 | create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 23 | base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 24 | - platform: linux 25 | create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 26 | base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 27 | - platform: macos 28 | create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 29 | base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 30 | - platform: web 31 | create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 32 | base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 33 | - platform: windows 34 | create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 35 | base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /lib/widgets/Utils/scroll_animation.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ScrollAnimationWidget extends StatefulWidget { 4 | const ScrollAnimationWidget({ 5 | Key? key, 6 | this.duration = const Duration(milliseconds: 1500), 7 | this.deltaY = 20, 8 | this.curve = Curves.fastOutSlowIn, 9 | required this.child, 10 | }) : super(key: key); 11 | 12 | final Duration duration; 13 | final double deltaY; 14 | final Widget child; 15 | final Curve curve; 16 | 17 | @override 18 | ScrollAnimationWidgetState createState() => ScrollAnimationWidgetState(); 19 | } 20 | 21 | class ScrollAnimationWidgetState extends State 22 | with SingleTickerProviderStateMixin { 23 | AnimationController? controller; 24 | 25 | @override 26 | void initState() { 27 | super.initState(); 28 | controller = AnimationController( 29 | duration: widget.duration, 30 | vsync: this, 31 | ) 32 | ..forward() 33 | ..addListener(() { 34 | if (controller!.isCompleted) { 35 | controller!.repeat(); 36 | } 37 | }); 38 | } 39 | 40 | @override 41 | void dispose() { 42 | controller!.dispose(); 43 | 44 | super.dispose(); 45 | } 46 | 47 | /// convert 0-1 to 0-1-0 48 | double scrollAnimation(double value) => 49 | 2.5 * (0.5 - (0.5 - widget.curve.transform(value)).abs()); 50 | 51 | @override 52 | Widget build(BuildContext context) { 53 | return AnimatedBuilder( 54 | animation: controller!, 55 | builder: (context, child) => Transform.translate( 56 | offset: Offset(0, widget.deltaY * scrollAnimation(controller!.value)), 57 | child: Transform.scale( 58 | scale: (1-controller!.value), 59 | child: child, 60 | ), 61 | ), 62 | child: widget.child, 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 10 | 18 | 22 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /data/teams.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Organizers", 4 | "id": "0", 5 | "members": [ 6 | { 7 | "name": "Shatanik Mahanty", 8 | "title": "Founder", 9 | "image": "https://i.imgur.com/1Yd49vH.jpeg", 10 | "linkedIn": "https://www.linkedin.com/in/shatanikmahanty/", 11 | "github": "https://github.com/shatanikmahanty/", 12 | "twitter": "https://twitter.com/MahantyShatanik" 13 | }, 14 | { 15 | "name": "Prosenjit Swarnakar", 16 | "title": "Co-Founder", 17 | "image": "https://i.imgur.com/kE7kqq8.jpeg", 18 | "linkedIn": "https://www.linkedin.com/in/prosenjit-swarnakar-5baa59236/", 19 | "github": "https://github.com/PROSENJIT-RONI/", 20 | "twitter": "https://twitter.com/ProsenjitSwarn5" 21 | }, 22 | { 23 | "name": "Sayan Mukherjee", 24 | "title": "Organizer", 25 | "image": "https://i.imgur.com/iJhYOE7_d.webp?maxwidth=760&fidelity=grand", 26 | "linkedIn": "https://www.linkedin.com/in/sayan-mukherjee-8946a3207/", 27 | "github": "https://github.com/sayanm16", 28 | "twitter": "https://twitter.com/SayanMu79522282" 29 | }, 30 | { 31 | "name": "Manish Kr. Barnwal", 32 | "title": "Organizer", 33 | "image": "https://i.imgur.com/Zf443Hd.png", 34 | "linkedIn": "https://www.linkedin.com/in/imanishbarnwal/", 35 | "github": "https://github.com/imanishbarnwal", 36 | "twitter": "https://twitter.com/imanishbarnwal" 37 | } 38 | ] 39 | }, 40 | { 41 | "name": "Outreach", 42 | "id": "1", 43 | "members": [ 44 | ] 45 | }, 46 | { 47 | "id": "2", 48 | "name": "Designers", 49 | "members": [ 50 | ] 51 | }, 52 | { 53 | "id": "3", 54 | "name": "Project Leads", 55 | "members": [ 56 | ] 57 | }, 58 | { 59 | "id": "4", 60 | "name": "Sponsor Relations", 61 | "members": [ 62 | ] 63 | } 64 | ] 65 | -------------------------------------------------------------------------------- /lib/widgets/Auth/page_view/login_intro_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class LoginIntroPage extends StatelessWidget { 4 | final String title, subtitle; 5 | final String imagePath; 6 | 7 | const LoginIntroPage({ 8 | Key? key, 9 | required this.title, 10 | required this.subtitle, 11 | required this.imagePath, 12 | }) : super(key: key); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return ClipRRect( 17 | borderRadius: BorderRadius.circular(8.0), 18 | child: Container( 19 | padding: const EdgeInsets.all(20), 20 | decoration: BoxDecoration( 21 | image: DecorationImage( 22 | image: AssetImage( 23 | imagePath, 24 | ), 25 | opacity: 0.7, 26 | fit: BoxFit.cover, 27 | ), 28 | color: Colors.black, 29 | ), 30 | child: Column( 31 | mainAxisAlignment: MainAxisAlignment.center, 32 | crossAxisAlignment: CrossAxisAlignment.center, 33 | children: [ 34 | Text( 35 | title, 36 | style: TextStyle( 37 | fontSize: MediaQuery.of(context).size.width < 1050 ? 80 : 100, 38 | fontFamily: "PublicSans", 39 | fontWeight: FontWeight.w800, 40 | foreground: Paint() 41 | ..strokeWidth = 3 42 | ..style = PaintingStyle.stroke 43 | ..color = Colors.white, 44 | ), 45 | ), 46 | const SizedBox( 47 | height: 15, 48 | ), 49 | Text( 50 | subtitle, 51 | textAlign: TextAlign.center, 52 | style: const TextStyle( 53 | fontSize: 25, 54 | fontFamily: "PublicSans", 55 | fontWeight: FontWeight.w600, 56 | color: Colors.white, 57 | ), 58 | ), 59 | ], 60 | ), 61 | ), 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/widgets/Utils/common_widgets.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ocyclient/widgets/Utils/snackbar.dart'; 3 | import 'package:url_launcher/url_launcher_string.dart'; 4 | 5 | Widget getIconButton( 6 | {required String title, required Function func, required IconData icon}) { 7 | return GestureDetector( 8 | onTap: () { 9 | func(); 10 | }, 11 | child: MouseRegion( 12 | cursor: SystemMouseCursors.click, 13 | child: getIconButtonBody( 14 | title, 15 | icon, 16 | ), 17 | ), 18 | ); 19 | } 20 | 21 | Widget getIconButtonBody(String title, IconData icon) { 22 | return Row( 23 | children: [ 24 | Card( 25 | shape: RoundedRectangleBorder( 26 | borderRadius: BorderRadius.circular(10), 27 | ), 28 | child: SizedBox( 29 | width: 30, 30 | height: 30, 31 | child: getIconForButton(icon), 32 | ), 33 | ), 34 | const SizedBox( 35 | width: 10, 36 | ), 37 | getTextForButton(title) 38 | ], 39 | ); 40 | } 41 | 42 | Widget getTextForButton(String label, {Color? color}) { 43 | return Text( 44 | label, 45 | style: TextStyle( 46 | color: color ?? Colors.white, 47 | fontWeight: FontWeight.bold, 48 | fontSize: 19, 49 | fontFamily: "PublicSans", 50 | ), 51 | ); 52 | } 53 | 54 | Widget getIconForButton(IconData icon) { 55 | return Icon( 56 | icon, 57 | color: const Color(0xff0f254e), 58 | size: 15, 59 | ); 60 | } 61 | 62 | 63 | Widget getFooterSocialButton(IconData icon, {String? link}) { 64 | return GestureDetector( 65 | onTap: () { 66 | if (link == null) { 67 | showToast("Coming soon"); 68 | } else { 69 | launchUrlString(link); 70 | } 71 | }, 72 | child: Card( 73 | shape: RoundedRectangleBorder( 74 | borderRadius: BorderRadius.circular(10), 75 | ), 76 | child: SizedBox( 77 | width: 30, 78 | height: 30, 79 | child: MouseRegion( 80 | cursor: SystemMouseCursors.click, 81 | child: getIconForButton(icon), 82 | ), 83 | ), 84 | ), 85 | ); 86 | } 87 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion flutter.compileSdkVersion 30 | 31 | compileOptions { 32 | sourceCompatibility JavaVersion.VERSION_1_8 33 | targetCompatibility JavaVersion.VERSION_1_8 34 | } 35 | 36 | kotlinOptions { 37 | jvmTarget = '1.8' 38 | } 39 | 40 | sourceSets { 41 | main.java.srcDirs += 'src/main/kotlin' 42 | } 43 | 44 | defaultConfig { 45 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 46 | // applicationId "com.ocy.ocyclient" 47 | applicationId "com.ocy.first-ocy-setup" 48 | minSdkVersion flutter.minSdkVersion 49 | targetSdkVersion flutter.targetSdkVersion 50 | versionCode flutterVersionCode.toInteger() 51 | versionName flutterVersionName 52 | } 53 | 54 | buildTypes { 55 | release { 56 | // TODO: Add your own signing config for the release build. 57 | // Signing with the debug keys for now, so `flutter run --release` works. 58 | signingConfig signingConfigs.debug 59 | } 60 | } 61 | } 62 | 63 | flutter { 64 | source '../..' 65 | } 66 | 67 | dependencies { 68 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 69 | } 70 | -------------------------------------------------------------------------------- /lib/blocs/teams_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'dart:convert'; 3 | import 'package:http/http.dart'; 4 | import 'package:ocyclient/models/team/team_model.dart'; 5 | 6 | /// {@category Blocs} 7 | class TeamsBloc extends ChangeNotifier { 8 | 9 | ///API URL for teams 10 | final Uri teamsUrl = Uri.parse( 11 | "https://raw.githubusercontent.com/OpenCodeyard/ocyclient/dev/data/teams.json?t=current%20timestamp", 12 | ); 13 | 14 | ///List of teams 15 | List _teams = []; 16 | 17 | List get teams => _teams; 18 | 19 | ///Handles team loading state 20 | bool _isLoading = false; 21 | 22 | bool get isLoading => _isLoading; 23 | 24 | ///Handles error state 25 | bool _hasError = false; 26 | 27 | bool get hasError => _hasError; 28 | 29 | ///Stores error message in case of an error 30 | String _errorMessage = ""; 31 | 32 | String get errorMessage => _errorMessage; 33 | 34 | ///Running fetch logic at app start from constructor 35 | TeamsBloc() { 36 | _fetchTeams(); 37 | } 38 | 39 | ///Gets list of team for org from Github API 40 | Future _fetchTeams() async { 41 | _isLoading = true; 42 | notifyListeners(); 43 | try { 44 | 45 | ///Gets list of teams from API 46 | final response = await get(teamsUrl); 47 | if (response.statusCode == 200) { 48 | final data = json.decode(response.body); 49 | 50 | ///Converts json team data to list of dart objects 51 | _teams = List.from(data.map((json) { 52 | return Team.fromJson(json); 53 | }).toList()); 54 | _isLoading = false; 55 | notifyListeners(); 56 | } else { 57 | _hasError = true; 58 | _errorMessage = "Something went wrong"; 59 | notifyListeners(); 60 | } 61 | } catch (e) { 62 | 63 | ///Handle errors here 64 | 65 | _hasError = true; 66 | if (kDebugMode) { 67 | print(e.toString()); 68 | } 69 | _errorMessage = "Something went wrong"; 70 | notifyListeners(); 71 | } 72 | } 73 | 74 | ///Gets single team object using ID 75 | ///Returns null if not found 76 | Team? getTeam(String id) { 77 | for (Team tm in teams) { 78 | if (tm.id == id) { 79 | return tm; 80 | } 81 | } 82 | return null; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/external/github_sign_in/lib/src/github_sign_in_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:webview_flutter/webview_flutter.dart'; 3 | 4 | class GitHubSignInPage extends StatefulWidget { 5 | final String url; 6 | final String redirectUrl; 7 | final bool clearCache; 8 | final String title; 9 | final bool? centerTitle; 10 | final String? userAgent; 11 | 12 | const GitHubSignInPage( 13 | {Key? key, 14 | required this.url, 15 | required this.redirectUrl, 16 | this.userAgent, 17 | this.clearCache = true, 18 | this.title = "", 19 | this.centerTitle}) 20 | : super(key: key); 21 | 22 | @override 23 | State createState() => _GitHubSignInPageState(); 24 | } 25 | 26 | class _GitHubSignInPageState extends State { 27 | static const String _userAgentMacOSX = 28 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36"; 29 | 30 | @override 31 | void initState() { 32 | super.initState(); 33 | } 34 | 35 | @override 36 | Widget build(BuildContext context) { 37 | return Scaffold( 38 | appBar: AppBar( 39 | title: Text(widget.title), 40 | centerTitle: widget.centerTitle, 41 | ), 42 | body: WebView( 43 | initialUrl: widget.url, 44 | userAgent: widget.userAgent ?? _userAgentMacOSX, 45 | javascriptMode: JavascriptMode.unrestricted, 46 | onWebViewCreated: (WebViewController controller) { 47 | if (widget.clearCache) { 48 | controller.clearCache(); 49 | CookieManager manager = CookieManager(); 50 | manager.clearCookies(); 51 | } 52 | }, 53 | onPageFinished: (url) { 54 | if (url.contains("error=")) { 55 | Navigator.of(context).pop( 56 | Exception(Uri.parse(url).queryParameters["error"]), 57 | ); 58 | } else if (url.startsWith(widget.redirectUrl)) { 59 | Navigator.of(context).pop( 60 | url.replaceFirst("${widget.redirectUrl}?code=", "").trim()); 61 | } 62 | }, 63 | )); 64 | } 65 | 66 | @override 67 | void dispose() { 68 | super.dispose(); 69 | // _wv.dispose(); 70 | // _wv.close(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/blocs/projects_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:flutter/foundation.dart'; 3 | import 'package:flutter_dotenv/flutter_dotenv.dart'; 4 | import 'package:ocyclient/configs/config.dart'; 5 | import 'package:ocyclient/models/project/project_model.dart'; 6 | 7 | /// {@category Blocs} 8 | class ProjectsBloc extends ChangeNotifier { 9 | Dio dio = Dio(); 10 | 11 | List _projects = []; 12 | 13 | List get projects => _projects; 14 | 15 | bool _isProjectsLoading = true; 16 | 17 | bool get isProjectsLoading => _isProjectsLoading; 18 | 19 | ///Gets list of projects for org from Github API 20 | void getProjects() async { 21 | String? token = dotenv.env[Config.envGhAccessToken]; 22 | 23 | dio.options.headers["Authorization"] = "token $token"; 24 | dio.options.headers["accept"] = "application/vnd.github.v3+json"; 25 | 26 | dio 27 | .get( 28 | "${Config.ghRootUrl}${Config.ghOrganisationsApi}/${Config.ghOrganisationName}/${Config.ghReposApi}", 29 | ) 30 | .then((value) async { 31 | List projectsResponse = value.data; 32 | 33 | ///Running expensive function in a separate isolate 34 | _projects = await compute(parseResponseIntoList, projectsResponse); 35 | 36 | int i = 0; 37 | for (var project in projectsResponse) { 38 | ///Gets list of contributors for all projects 39 | var responseContributors = await dio.get(project["contributors_url"]); 40 | List contributors = await compute( 41 | getImageUrls, 42 | responseContributors.data as List, 43 | ); 44 | _projects[i].contributors = contributors; 45 | i++; 46 | } 47 | 48 | ///Sorts projects based on star count 49 | _projects.sort((a,b) => b.starCount.compareTo(a.starCount)); 50 | 51 | _isProjectsLoading = false; 52 | notifyListeners(); 53 | }); 54 | } 55 | } 56 | 57 | ///Top level functions because it will be used in an isolate 58 | ///Warning : Putting it inside the class will cause error 59 | 60 | List parseResponseIntoList(List projects) { 61 | return projects.map((data) => ProjectModel.fromJson(data)).toList(); 62 | } 63 | 64 | List getImageUrls(List users) { 65 | List toBeReturned = []; 66 | for (var user in users) { 67 | toBeReturned.add("${user["avatar_url"]}^${user["html_url"]}"); 68 | } 69 | 70 | return toBeReturned; 71 | } 72 | -------------------------------------------------------------------------------- /web/github_login.js: -------------------------------------------------------------------------------- 1 | async function initLogin(isLinkOperation){ 2 | var provider = new firebase.auth.GithubAuthProvider(); 3 | 4 | provider.addScope('repo'); 5 | provider.addScope('user'); 6 | provider.addScope('gist'); 7 | provider.addScope('user:email'); 8 | provider.setCustomParameters({ 9 | 'allow_signup': 'true' 10 | }); 11 | 12 | var result; 13 | 14 | if(!isLinkOperation.value){ 15 | result = await firebase 16 | .auth() 17 | .signInWithPopup(provider) 18 | .then((result) => { 19 | /** @type {firebase.auth.OAuthCredential} */ 20 | var credential = result.credential; 21 | 22 | // This gives you a GitHub Access Token. You can use it to access the GitHub API. 23 | var token = credential.accessToken; 24 | 25 | // The signed-in user info. 26 | var user = result.user; 27 | 28 | return token; 29 | 30 | }).catch((error) => { 31 | // Handle Errors here. 32 | var errorCode = error.code; 33 | var errorMessage = error.message; 34 | // The email of the user's account used. 35 | var email = error.email; 36 | // The firebase.auth.AuthCredential type that was used. 37 | var credential = error.credential; 38 | 39 | return "error:" + errorMessage; 40 | }); 41 | 42 | return result; 43 | } else{ 44 | result = await firebase 45 | .auth() 46 | .currentUser 47 | .linkWithPopup(provider) 48 | .then((result) => { 49 | /** @type {firebase.auth.OAuthCredential} */ 50 | var credential = result.credential; 51 | 52 | // This gives you a GitHub Access Token. You can use it to access the GitHub API. 53 | var token = credential.accessToken; 54 | 55 | // The signed-in user info. 56 | var user = result.user; 57 | 58 | return token; 59 | 60 | }).catch((error) => { 61 | // Handle Errors here. 62 | var errorCode = error.code; 63 | var errorMessage = error.message; 64 | // The email of the user's account used. 65 | var email = error.email; 66 | // The firebase.auth.AuthCredential type that was used. 67 | var credential = error.credential; 68 | 69 | return "error:" + errorMessage; 70 | }); 71 | 72 | return result; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lib/blocs/locale_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:get/get.dart'; 3 | import 'package:ocyclient/configs/config.dart'; 4 | import 'package:ocyclient/models/localization/language.dart'; 5 | import 'package:shared_preferences/shared_preferences.dart'; 6 | 7 | class LocaleBLoc extends ChangeNotifier { 8 | static const String english = "en"; 9 | static const String bengali = "bn"; 10 | static const String hindi = "hn"; 11 | static const String marathi ="mt" 12 | Locale _currentLocale = const Locale(english, "US"); 13 | 14 | Locale get currentLocale => _currentLocale; 15 | 16 | LocaleBLoc(GlobalKey navigatorKey) { 17 | loadLocale(navigatorKey); 18 | } 19 | 20 | void changeLanguage(Language language, context) async { 21 | SharedPreferences sp = await SharedPreferences.getInstance(); 22 | 23 | Locale locale; 24 | switch (language.languageCode) { 25 | case english: 26 | locale = Locale(language.languageCode, "US"); 27 | break; 28 | case bengali: 29 | locale = Locale(language.languageCode, "IN"); 30 | break; 31 | case hindi: 32 | locale = Locale(language.languageCode, "IN"); 33 | break; 34 | case marathi: 35 | locale = Locale(language.languageCode,"IN"); 36 | break; 37 | default: 38 | locale = Locale(language.languageCode, 'US'); 39 | } 40 | _currentLocale = locale; 41 | notifyListeners(); 42 | 43 | Get.updateLocale(currentLocale); 44 | 45 | sp.setString("currentLanguageName", getCurrentSelectedLanguage().name); 46 | sp.setString("currentLanguageCode", _currentLocale.languageCode); 47 | sp.setString( 48 | "currentLanguageCountryCode", _currentLocale.countryCode ?? "NULL"); 49 | } 50 | 51 | Language getCurrentSelectedLanguage() { 52 | for (Language l in Config.languageList) { 53 | if ((currentLocale.countryCode ?? "") == l.countryCode) { 54 | if (currentLocale.languageCode == l.languageCode) { 55 | return l; 56 | } 57 | } else if (currentLocale.countryCode == null && l.countryCode == "") { 58 | if (currentLocale.languageCode == l.languageCode) { 59 | return l; 60 | } 61 | } 62 | } 63 | 64 | return Language("English", "US", "en"); 65 | } 66 | 67 | void loadLocale(GlobalKey navigatorKey) async { 68 | SharedPreferences sp = await SharedPreferences.getInstance(); 69 | 70 | String? countryCode = sp.getString("currentLanguageCountryCode"); 71 | String? langCode = sp.getString("currentLanguageCode") ?? "en"; 72 | 73 | if (countryCode == "NULL" || countryCode == null) { 74 | countryCode = "US"; 75 | } 76 | 77 | _currentLocale = Locale( 78 | langCode, 79 | countryCode, 80 | ); 81 | 82 | Get.updateLocale(currentLocale); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/widgets/Teams/member/member_horizontal.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 3 | import 'package:ocyclient/models/team/team_model.dart'; 4 | import 'package:ocyclient/widgets/Utils/common_widgets.dart'; 5 | import 'package:url_launcher/url_launcher_string.dart'; 6 | 7 | class MemberHorizontal extends StatelessWidget { 8 | final Member member; 9 | 10 | const MemberHorizontal({Key? key, required this.member}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Padding( 15 | padding: const EdgeInsets.symmetric( 16 | horizontal: 45.0, 17 | vertical: 10, 18 | ), 19 | child: Row( 20 | mainAxisAlignment: MainAxisAlignment.start, 21 | crossAxisAlignment: CrossAxisAlignment.start, 22 | children: [ 23 | ClipRRect( 24 | borderRadius: BorderRadius.circular(15.0), 25 | child: Image.network( 26 | member.image, 27 | width: 120, 28 | height: 120, 29 | fit: BoxFit.cover, 30 | ), 31 | ), 32 | const SizedBox( 33 | width: 20, 34 | ), 35 | memberDetails(member), 36 | ], 37 | ), 38 | ); 39 | } 40 | 41 | Widget memberDetails(Member member) { 42 | return Column( 43 | mainAxisAlignment: MainAxisAlignment.start, 44 | crossAxisAlignment: CrossAxisAlignment.start, 45 | children: [ 46 | Text( 47 | member.name, 48 | style: const TextStyle( 49 | fontSize: 20, 50 | color: Colors.white, 51 | fontWeight: FontWeight.bold, 52 | fontFamily: "PublicSans"), 53 | ), 54 | const SizedBox( 55 | height: 15, 56 | ), 57 | Text( 58 | member.title, 59 | style: const TextStyle( 60 | fontSize: 17, color: Colors.white, fontFamily: "PublicSans"), 61 | ), 62 | const SizedBox( 63 | height: 15, 64 | ), 65 | SizedBox( 66 | height: 50, 67 | child: ListView( 68 | scrollDirection: Axis.horizontal, 69 | shrinkWrap: true, 70 | physics: const BouncingScrollPhysics(), 71 | children: [ 72 | if ((member.linkedIn ?? "").isNotEmpty) 73 | getIconButton( 74 | title: "", 75 | func: () { 76 | launchUrlString(member.linkedIn ?? ""); 77 | }, 78 | icon: FontAwesomeIcons.linkedinIn, 79 | ), 80 | if ((member.github ?? "").isNotEmpty) 81 | getIconButton( 82 | title: "", 83 | func: () { 84 | launchUrlString(member.github ?? ""); 85 | }, 86 | icon: FontAwesomeIcons.github, 87 | ), 88 | if ((member.twitter ?? "").isNotEmpty) 89 | getIconButton( 90 | title: "", 91 | func: () { 92 | launchUrlString(member.twitter ?? ""); 93 | }, 94 | icon: FontAwesomeIcons.twitter, 95 | ), 96 | ], 97 | ), 98 | ), 99 | ], 100 | ); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /lib/widgets/Home/sub_pages/events.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:line_icons/line_icons.dart'; 3 | 4 | class UpcomingEvents extends StatelessWidget { 5 | const UpcomingEvents({Key? key}) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | Size size = MediaQuery.of(context).size; 10 | 11 | return Container( 12 | padding: EdgeInsets.all(size.width < 900 ? 30 : 15), 13 | color: Colors.white, 14 | width: size.width, 15 | // height: 400, 16 | child: Column( 17 | crossAxisAlignment: CrossAxisAlignment.start, 18 | children: [ 19 | SizedBox( 20 | height: size.height * 0.1, 21 | ), 22 | size.width < 900 23 | ? Column( 24 | crossAxisAlignment: CrossAxisAlignment.start, 25 | children: [ 26 | eventZone(size), 27 | const SizedBox( 28 | height: 50, 29 | ), 30 | ], 31 | ) 32 | : Row( 33 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 34 | crossAxisAlignment: CrossAxisAlignment.start, 35 | children: [ 36 | Column( 37 | children: "EVENTS" 38 | .split("") 39 | .map((string) => Text( 40 | string, 41 | style: TextStyle( 42 | fontFamily: "PublicSans", 43 | fontWeight: FontWeight.bold, 44 | fontSize: size.width > 1100 ? 70 : 60, 45 | letterSpacing: 4, 46 | foreground: Paint() 47 | ..strokeWidth = 1 48 | ..style = PaintingStyle.stroke 49 | ..color = const Color( 50 | 0xff071a2b, 51 | ), 52 | ), 53 | )) 54 | .toList(), 55 | ), 56 | eventZone(size), 57 | eventZone(size), 58 | ], 59 | ), 60 | SizedBox( 61 | height: size.height * 0.1, 62 | ), 63 | ], 64 | ), 65 | ); 66 | } 67 | 68 | Widget eventZone(Size size) { 69 | return Column( 70 | crossAxisAlignment: CrossAxisAlignment.start, 71 | children: [ 72 | const SizedBox( 73 | height: 30, 74 | ), 75 | SizedBox( 76 | width: size.width < 900 77 | ? size.width 78 | : size.width > 1050 79 | ? 380 80 | : size.width * 0.3, 81 | child: Text( 82 | "We conduct as well as participate in frequent events spanning over" 83 | " a wide range of topics from technology, " 84 | "games, awareness campaigns, etc.", 85 | style: TextStyle( 86 | fontSize: size.width < 1000 ? 16 : 18, 87 | fontFamily: "PublicSans", 88 | fontWeight: FontWeight.bold, 89 | ), 90 | ), 91 | ), 92 | const SizedBox( 93 | height: 20, 94 | ), 95 | TextButton.icon( 96 | onPressed: () {}, 97 | icon: const Text( 98 | "All events", 99 | style: TextStyle( 100 | color: Colors.blue, 101 | ), 102 | ), 103 | label: const Icon( 104 | LineIcons.arrowRight, 105 | color: Colors.blue, 106 | ), 107 | ), 108 | ], 109 | ); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /lib/widgets/Home/sub_pages/intro.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 3 | import 'package:ocyclient/configs/config.dart'; 4 | import 'package:ocyclient/widgets/Utils/common_widgets.dart'; 5 | import 'package:ocyclient/widgets/Utils/snackbar.dart'; 6 | import 'package:responsive_grid/responsive_grid.dart'; 7 | import 'package:url_launcher/url_launcher_string.dart'; 8 | 9 | class Intro extends StatelessWidget { 10 | const Intro({Key? key}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | Size size = MediaQuery.of(context).size; 15 | 16 | return Stack( 17 | children: [ 18 | Container( 19 | height: size.width > 700 ? size.height : size.height / 1.8, 20 | decoration: BoxDecoration( 21 | image: DecorationImage( 22 | image: const AssetImage( 23 | "assets/images/welcome.jpg", 24 | ), 25 | fit: size.width < 700 ? BoxFit.fill : BoxFit.cover, 26 | opacity: 0.8, 27 | ), 28 | color: const Color(0xff152839), 29 | ), 30 | width: MediaQuery.of(context).size.width, 31 | // height: MediaQuery.of(context).size.height, 32 | child: Row( 33 | children: [ 34 | logoDescription(size), 35 | ], 36 | ), 37 | ), 38 | ], 39 | ); 40 | } 41 | 42 | Widget logoDescription(Size size) { 43 | return SizedBox( 44 | width: size.width, 45 | child: Column( 46 | mainAxisAlignment: MainAxisAlignment.center, 47 | children: [ 48 | const Spacer(), 49 | const SizedBox( 50 | height: 50, 51 | ), 52 | Row( 53 | mainAxisAlignment: MainAxisAlignment.center, 54 | children: [ 55 | Text( 56 | "OPEN CODEYARD", 57 | style: TextStyle( 58 | fontSize: size.width < 500 59 | ? 40 60 | : size.width < 1200 61 | ? 50 62 | : 100, 63 | fontWeight: FontWeight.bold, 64 | fontFamily: "PublicSans", 65 | color: Colors.white), 66 | ) 67 | ], 68 | ), 69 | const Spacer(), 70 | ResponsiveGridList( 71 | desiredItemWidth: size.width < 700 ? 50 : 140, 72 | scroll: false, 73 | rowMainAxisAlignment: MainAxisAlignment.center, 74 | minSpacing: 20, 75 | children: [ 76 | getIconButton( 77 | title: size.width < 700 ? "" : "LinkedIn", 78 | func: () { 79 | launchUrlString(Config.linkedInUrl); 80 | }, 81 | icon: FontAwesomeIcons.linkedinIn, 82 | ), 83 | getIconButton( 84 | title: size.width < 700 ? "" : "Telegram", 85 | func: () { 86 | launchUrlString(Config.telegramUrl); 87 | }, 88 | icon: FontAwesomeIcons.telegram, 89 | ), 90 | getIconButton( 91 | title: size.width < 700 ? "" : "GitHub", 92 | func: () { 93 | launchUrlString(Config.ghUrl); 94 | }, 95 | icon: FontAwesomeIcons.github, 96 | ), 97 | getIconButton( 98 | title: size.width < 700 ? "" : "Discord", 99 | func: () { 100 | showToast("Coming Soon!"); 101 | }, 102 | icon: FontAwesomeIcons.discord, 103 | ), 104 | ], 105 | ), 106 | const SizedBox( 107 | height: 10, 108 | ), 109 | ], 110 | ), 111 | ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: ocyclient 2 | description: Official client side application of Open Codeyard 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 0.8.1-alpha+12 19 | 20 | environment: 21 | sdk: ">=2.18.6 <3.0.0" 22 | 23 | # Dependencies specify other packages that your package needs in order to work. 24 | # To automatically upgrade your package dependencies to the latest versions 25 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 26 | # dependencies can be manually updated by changing the version numbers below to 27 | # the latest version available on pub.dev. To see which dependencies have newer 28 | # versions available, run `flutter pub outdated`. 29 | dependencies: 30 | flutter: 31 | sdk: flutter 32 | flutter_localizations: 33 | sdk: flutter 34 | flutter_web_plugins: 35 | sdk: flutter 36 | 37 | #ux 38 | flutter_markdown: ^0.6.10+5 39 | html2md: ^1.2.6 40 | carousel_slider: ^4.1.1 41 | responsive_grid: ^2.1.0 42 | 43 | #Icons 44 | line_icons: ^2.0.1 45 | font_awesome_flutter: ^10.1.0 46 | 47 | #State management 48 | provider: ^6.0.3 49 | get: ^4.6.5 50 | 51 | #Session management 52 | shared_preferences: 2.0.15 53 | 54 | # Extras 55 | url_launcher: ^6.1.6 56 | webview_flutter: ^3.0.4 57 | step_progress_indicator: ^1.0.2 58 | fluttertoast: ^8.0.9 59 | face_pile: ^0.0.2 60 | intl: ^0.17.0 61 | 62 | #Networking 63 | http: ^0.13.5 64 | 65 | #Firebase dependencies 66 | firebase_auth: ^3.11.1 67 | firebase_core: ^1.24.0 68 | cloud_firestore: ^3.5.0 69 | 70 | #Web 71 | universal_html: ^2.0.8 72 | js: ^0.6.3 73 | 74 | #Login Providers 75 | google_sign_in: ^5.4.2 76 | 77 | #Apis 78 | dio: ^4.0.6 79 | 80 | #Api key management 81 | flutter_dotenv: ^5.0.2 82 | 83 | dev_dependencies: 84 | flutter_test: 85 | sdk: flutter 86 | 87 | # The "flutter_lints" package below contains a set of recommended lints to 88 | # encourage good coding practices. The lint set provided by the package is 89 | # activated in the `analysis_options.yaml` file located at the root of your 90 | # package. See that file for information about deactivating specific lint 91 | # rules and activating additional ones. 92 | flutter_lints: ^2.0.1 93 | 94 | # For information on the generic Dart part of this file, see the 95 | # following page: https://dart.dev/tools/pub/pubspec 96 | 97 | # The following section is specific to Flutter. 98 | flutter: 99 | 100 | # The following line ensures that the Material Icons font is 101 | # included with your application, so that you can use the icons in 102 | # the material Icons class. 103 | uses-material-design: true 104 | 105 | # To add assets to your application, add an assets section, like this: 106 | assets: 107 | - assets/images/ 108 | - env 109 | 110 | fonts: 111 | - family: PublicSans 112 | fonts: 113 | - asset: assets/fonts/PublicSans_Regular.otf 114 | - asset: assets/fonts/PublicSans_ExtraBold.otf 115 | weight: 700 116 | - asset: assets/fonts/PublicSans_Bold.otf 117 | weight: 500 118 | -------------------------------------------------------------------------------- /lib/widgets/Teams/member/member_vertical.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 3 | import 'package:ocyclient/models/team/team_model.dart'; 4 | import 'package:ocyclient/widgets/Utils/common_widgets.dart'; 5 | import 'package:url_launcher/url_launcher_string.dart'; 6 | 7 | class MemberVertical extends StatelessWidget { 8 | final Member member; 9 | 10 | const MemberVertical({Key? key, required this.member}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Padding( 15 | padding: const EdgeInsets.symmetric( 16 | horizontal: 45.0, 17 | vertical: 10, 18 | ), 19 | child: Column( 20 | mainAxisAlignment: MainAxisAlignment.start, 21 | crossAxisAlignment: CrossAxisAlignment.start, 22 | children: [ 23 | Row( 24 | crossAxisAlignment: CrossAxisAlignment.start, 25 | children: [ 26 | ClipRRect( 27 | borderRadius: BorderRadius.circular(15.0), 28 | child: Image.network( 29 | member.image, 30 | width: 140, 31 | height: 140, 32 | fit: BoxFit.cover, 33 | ), 34 | ), 35 | const SizedBox( 36 | width: 20, 37 | ), 38 | SizedBox( 39 | height: 140, 40 | width: 60, 41 | child: Center( 42 | child: ListView( 43 | scrollDirection: Axis.vertical, 44 | shrinkWrap: true, 45 | physics: const BouncingScrollPhysics(), 46 | children: [ 47 | if ((member.linkedIn ?? "").isNotEmpty) 48 | getIconButton( 49 | title: "", 50 | func: () { 51 | launchUrlString(member.linkedIn ?? ""); 52 | }, 53 | icon: FontAwesomeIcons.linkedinIn, 54 | ), 55 | const SizedBox( 56 | height: 10, 57 | ), 58 | if ((member.github ?? "").isNotEmpty) 59 | getIconButton( 60 | title: "", 61 | func: () { 62 | launchUrlString(member.github ?? ""); 63 | }, 64 | icon: FontAwesomeIcons.github, 65 | ), 66 | if ((member.twitter ?? "").isNotEmpty) 67 | getIconButton( 68 | title: "", 69 | func: () { 70 | launchUrlString(member.twitter ?? ""); 71 | }, 72 | icon: FontAwesomeIcons.twitter, 73 | ), 74 | ], 75 | ), 76 | ), 77 | ), 78 | ], 79 | ), 80 | const SizedBox( 81 | height: 20, 82 | ), 83 | memberDetails(member), 84 | ], 85 | ), 86 | ); 87 | } 88 | 89 | Widget memberDetails(Member member) { 90 | return Column( 91 | mainAxisAlignment: MainAxisAlignment.start, 92 | crossAxisAlignment: CrossAxisAlignment.start, 93 | children: [ 94 | Text( 95 | member.name, 96 | style: const TextStyle( 97 | fontSize: 20, 98 | color: Colors.white, 99 | fontWeight: FontWeight.bold, 100 | fontFamily: "PublicSans"), 101 | ), 102 | const SizedBox( 103 | height: 15, 104 | ), 105 | Text( 106 | member.title, 107 | style: const TextStyle( 108 | fontSize: 17, color: Colors.white, fontFamily: "PublicSans"), 109 | ), 110 | const SizedBox( 111 | height: 15, 112 | ), 113 | ], 114 | ); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /lib/widgets/Profile/widgets/accounts.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 3 | import 'package:ocyclient/blocs/auth_bloc.dart'; 4 | import 'package:ocyclient/blocs/navigation_bloc.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | class AccountWidget extends StatelessWidget { 8 | const AccountWidget({Key? key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | AuthenticationBloc ab = Provider.of(context); 13 | 14 | NavigationBloc nb = Provider.of(context); 15 | 16 | Size size = MediaQuery.of(context).size; 17 | 18 | return Column( 19 | crossAxisAlignment: CrossAxisAlignment.start, 20 | children: [ 21 | Container( 22 | margin: const EdgeInsets.all(10), 23 | child: Text( 24 | "Accounts", 25 | style: TextStyle( 26 | fontWeight: FontWeight.bold, 27 | fontSize: size.width < 700 ? 25 : 40, 28 | fontFamily: "PublicSans", 29 | ), 30 | ), 31 | ), 32 | Container( 33 | margin: const EdgeInsets.all(10), 34 | child: SingleChildScrollView( 35 | scrollDirection: Axis.horizontal, 36 | child: Row( 37 | children: [ 38 | getAccountCard( 39 | ab, nb, "assets/images/google_logo.png", "Google", context), 40 | const SizedBox( 41 | width: 15, 42 | ), 43 | getAccountCard( 44 | ab, nb, "assets/images/github_logo.png", "Github", context) 45 | ], 46 | ), 47 | ), 48 | ), 49 | ], 50 | ); 51 | } 52 | 53 | Widget getAccountCard( 54 | AuthenticationBloc ab, 55 | NavigationBloc nb, 56 | String imagePath, 57 | String name, 58 | BuildContext context, 59 | ) { 60 | return Card( 61 | elevation: 3, 62 | shape: RoundedRectangleBorder( 63 | borderRadius: BorderRadius.circular(20), 64 | ), 65 | child: Container( 66 | padding: const EdgeInsets.all(20), 67 | width: 140, 68 | child: Column( 69 | crossAxisAlignment: CrossAxisAlignment.center, 70 | children: [ 71 | Image.asset( 72 | imagePath, 73 | height: 30, 74 | width: 30, 75 | ), 76 | const SizedBox( 77 | height: 20, 78 | ), 79 | MouseRegion( 80 | cursor: !ab.userModel.loginProvidersConnected.contains(name) 81 | ? SystemMouseCursors.click 82 | : SystemMouseCursors.basic, 83 | child: GestureDetector( 84 | onTap: () { 85 | if (!ab.userModel.loginProvidersConnected.contains(name)) { 86 | if (name == "Google") { 87 | ab.authWithGoogle(nb, true); 88 | } else { 89 | ab.authWithGithub(context, nb, true); 90 | } 91 | } 92 | }, 93 | child: Row( 94 | mainAxisSize: MainAxisSize.min, 95 | children: [ 96 | ab.userModel.loginProvidersConnected.contains(name) 97 | ? const Icon( 98 | FontAwesomeIcons.circleCheck, 99 | color: Colors.green, 100 | size: 15, 101 | ) 102 | : const Icon( 103 | FontAwesomeIcons.link, 104 | color: Colors.indigoAccent, 105 | size: 15, 106 | ), 107 | const SizedBox( 108 | width: 5, 109 | ), 110 | Text( 111 | name, 112 | style: const TextStyle( 113 | fontFamily: "PublicSans", 114 | fontWeight: FontWeight.bold, 115 | ), 116 | ), 117 | ], 118 | ), 119 | ), 120 | ), 121 | ], 122 | ), 123 | ), 124 | ); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /lib/widgets/Teams/team_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 3 | import 'package:ocyclient/models/team/team_model.dart'; 4 | import 'package:ocyclient/widgets/Teams/member/member_vertical.dart'; 5 | import 'package:ocyclient/widgets/Teams/member/member_horizontal.dart'; 6 | import 'package:responsive_grid/responsive_grid.dart'; 7 | 8 | class TeamCard extends StatefulWidget { 9 | final Size size; 10 | final String title; 11 | final List members; 12 | 13 | const TeamCard( 14 | {Key? key, 15 | required this.size, 16 | required this.title, 17 | required this.members}) 18 | : super(key: key); 19 | 20 | @override 21 | State createState() => _TeamCardState(); 22 | } 23 | 24 | class _TeamCardState extends State { 25 | bool isExpanded = true; 26 | 27 | @override 28 | void initState() { 29 | if (widget.members.isEmpty) { 30 | setState(() { 31 | isExpanded = false; 32 | }); 33 | } 34 | super.initState(); 35 | } 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | return Padding( 40 | padding: const EdgeInsets.symmetric(vertical: 25.0), 41 | child: Card( 42 | elevation: 8, 43 | shape: RoundedRectangleBorder( 44 | borderRadius: BorderRadius.circular(15), 45 | ), 46 | color: const Color(0xff152839), 47 | child: ExpansionTile( 48 | initiallyExpanded: widget.members.isNotEmpty, 49 | onExpansionChanged: (bool value) { 50 | setState(() { 51 | isExpanded = value; 52 | }); 53 | }, 54 | trailing: const SizedBox(), 55 | title: Padding( 56 | padding: const EdgeInsets.symmetric( 57 | horizontal: 8.0, 58 | vertical: 20, 59 | ), 60 | child: Row( 61 | children: [ 62 | const SizedBox( 63 | width: 22, 64 | ), 65 | Text( 66 | widget.title, 67 | style: TextStyle( 68 | fontFamily: "PublicSans", 69 | fontWeight: FontWeight.bold, 70 | color: Colors.white, 71 | fontSize: widget.size.width > 1100 72 | ? 40 73 | : widget.size.width > 800 74 | ? 30 75 | : 25, 76 | ), 77 | ), 78 | const Spacer(), 79 | Icon( 80 | isExpanded 81 | ? FontAwesomeIcons.circleMinus 82 | : FontAwesomeIcons.circlePlus, 83 | color: Colors.white, 84 | size: widget.size.width > 800 ? 40 : 25, 85 | ), 86 | if (widget.size.width > 800) 87 | const SizedBox( 88 | width: 22, 89 | ), 90 | ], 91 | ), 92 | ), 93 | children: [ 94 | if (widget.members.isNotEmpty) ...[ 95 | ResponsiveGridList( 96 | desiredItemWidth: 97 | widget.size.width < 480 ? widget.size.width - 50 : 430, 98 | scroll: false, 99 | rowMainAxisAlignment: MainAxisAlignment.start, 100 | children: List.generate( 101 | widget.members.length, 102 | (index) { 103 | Member member = widget.members[index]; 104 | return widget.size.width > 500 105 | ? MemberHorizontal(member: member) 106 | : MemberVertical(member: member); 107 | }, 108 | ), 109 | ), 110 | const SizedBox( 111 | height: 30, 112 | ), 113 | ] else ...[ 114 | const Text( 115 | "No members found", 116 | style: TextStyle( 117 | fontSize: 17, 118 | color: Colors.white, 119 | fontWeight: FontWeight.bold, 120 | fontFamily: "PublicSans"), 121 | ), 122 | const SizedBox( 123 | height: 30, 124 | ), 125 | ] 126 | ], 127 | ), 128 | ), 129 | ); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /lib/external/github_sign_in/lib/src/github_sign_in.dart: -------------------------------------------------------------------------------- 1 | @JS() 2 | library github_login; 3 | 4 | import 'dart:convert'; 5 | 6 | import 'package:flutter/material.dart'; 7 | import 'package:http/http.dart' as http; 8 | import 'package:js/js.dart'; 9 | import 'package:js/js_util.dart'; 10 | 11 | import 'package:flutter/foundation.dart'; 12 | 13 | import 'github_sign_in_page.dart'; 14 | import 'github_sign_in_result.dart'; 15 | 16 | @JS() 17 | external dynamic initLogin(ObjectYouWantToSend theObject); 18 | 19 | @JS() 20 | @anonymous 21 | class ObjectYouWantToSend { 22 | external factory ObjectYouWantToSend({ 23 | bool value, 24 | }); 25 | 26 | external bool get value; 27 | } 28 | 29 | class GitHubSignIn { 30 | final String clientId; 31 | final String clientSecret; 32 | final String redirectUrl; 33 | final String scope; 34 | final String title; 35 | final bool? centerTitle; 36 | final bool allowSignUp; 37 | final bool clearCache; 38 | final String? userAgent; 39 | 40 | final String _githubAuthorizedUrl = 41 | "https://github.com/login/oauth/authorize"; 42 | final String _githubAccessTokenUrl = 43 | "https://github.com/login/oauth/access_token"; 44 | 45 | GitHubSignIn({ 46 | required this.clientId, 47 | required this.clientSecret, 48 | required this.redirectUrl, 49 | this.scope = "user,gist,user:email", 50 | this.title = "", 51 | this.centerTitle, 52 | this.allowSignUp = true, 53 | this.clearCache = true, 54 | this.userAgent, 55 | }); 56 | 57 | Future signIn( 58 | BuildContext context, bool isLinkOperation) async { 59 | 60 | // let's authorize 61 | var authorizedResult; 62 | var cred; 63 | if (kIsWeb) { 64 | cred = await promiseToFuture(initLogin(ObjectYouWantToSend( 65 | value: isLinkOperation, 66 | ))); 67 | //push data into authorized result somehow 68 | 69 | } else { 70 | authorizedResult = await Navigator.of(context).push( 71 | MaterialPageRoute( 72 | builder: (context) => GitHubSignInPage( 73 | url: _generateAuthorizedUrl(), 74 | redirectUrl: redirectUrl, 75 | userAgent: userAgent, 76 | clearCache: clearCache, 77 | title: title, 78 | centerTitle: centerTitle, 79 | ), 80 | ), 81 | ); 82 | } 83 | 84 | GitHubSignInResult result; 85 | if (!kIsWeb) { 86 | if (authorizedResult == null || 87 | authorizedResult.toString().contains('access_denied')) { 88 | return GitHubSignInResult( 89 | GitHubSignInResultStatus.cancelled, 90 | errorMessage: "Sign In attempt has been cancelled.", 91 | ); 92 | } else if (authorizedResult is Exception) { 93 | return GitHubSignInResult( 94 | GitHubSignInResultStatus.failed, 95 | errorMessage: authorizedResult.toString(), 96 | ); 97 | } 98 | 99 | // exchange for access token 100 | String code = authorizedResult; 101 | var response = await http.post( 102 | Uri.parse(_githubAccessTokenUrl), 103 | headers: {"Accept": "application/json"}, 104 | body: { 105 | "client_id": clientId, 106 | "client_secret": clientSecret, 107 | "code": code 108 | }, 109 | ); 110 | 111 | if (response.statusCode == 200) { 112 | var body = json.decode(utf8.decode(response.bodyBytes)); 113 | result = GitHubSignInResult( 114 | GitHubSignInResultStatus.ok, 115 | token: body["access_token"], 116 | ); 117 | } else { 118 | result = GitHubSignInResult( 119 | GitHubSignInResultStatus.cancelled, 120 | errorMessage: 121 | "Unable to obtain token. Received: ${response.statusCode}", 122 | ); 123 | } 124 | } else { 125 | if (cred.toString().startsWith("error")) { 126 | result = GitHubSignInResult( 127 | GitHubSignInResultStatus.failed, 128 | errorMessage: cred.toString().split("error:")[1], 129 | ); 130 | } else { 131 | result = GitHubSignInResult( 132 | GitHubSignInResultStatus.ok, 133 | token: cred.toString(), 134 | ); 135 | } 136 | } 137 | return result; 138 | } 139 | 140 | String _generateAuthorizedUrl() { 141 | return "$_githubAuthorizedUrl?" 142 | "client_id=$clientId" 143 | "&redirect_uri=$redirectUrl" 144 | "&scope=$scope" 145 | "&allow_signup=$allowSignUp"; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /.firebase/hosting.YnVpbGRcd2Vi.cache: -------------------------------------------------------------------------------- 1 | favicon-16x16.png,1664637518602,92bc66de59f3616e0a8a8e197f479e47b38638b842cc0d87be6d9920efb198f8 2 | favicon-32x32.png,1664637518602,c2c805f5da7423cbca7a0cd94838f9e7dc33a7f3062eeebf6e1cf13164de6184 3 | favicon.ico,1664637518602,b8038bf2985bf999e62a693aab78f64ec2862b647497320d6d156bdf217b1209 4 | flutter.js,1672719538763,3b3a07d4c55d59c5461929dc37484dec4d38c90aca67f7c044eb85d9524889e6 5 | github_login.js,1664637518602,0650816d750e85c4f1324d98e6352d7872bfe1088286351942397cbd03a298c9 6 | manifest.json,1664637518623,3bbf45483e1a07534e51b47b66c259c203ca5d90d869babb904dad2ed2f8ad85 7 | assets/env,1662443822263,2af834b1162cfbc8b1c4630f645813d3be178d3034258f81901e30c166c04b01 8 | assets/assets/fonts/PublicSans_Bold.otf,1664637518484,18a3a82b3fd44249db46c9c69fd2e78db9731602954e54d45662c771f07832ec 9 | assets/assets/fonts/PublicSans_ExtraBold.otf,1664637518495,a3dfbe9afdf5b1fd7c2c32d4b8d80294912063b375525da37ce1e14d3113b153 10 | assets/assets/fonts/PublicSans_Regular.otf,1664637518495,02b82ce178e9b00896c6f626ef72541ea084878e086fc0fea1b5f8acef55ddd4 11 | assets/assets/images/add_skills.png,1664637518495,17bbcae95471496076577817d621245d5ab69e65018d862a5a6cdb2460b74d75 12 | assets/assets/images/events.jpg,1664637518506,36857078d09a3d650add84ec2a9eb2aa81792d7d38ed6d1a250256dcc115b8a9 13 | assets/assets/images/fork_icon.png,1664637518506,6d61940da8d1435ea29b43591cacefc441eb59f346c2e08990518f4ea3a4416a 14 | assets/assets/images/github_logo.png,1664637518506,ea8edc268426b5d63304a6a02d43c67fb542ce583ae44550086952c517e36a67 15 | assets/assets/images/google_logo.png,1664637518506,e73bcea8239c55ef8fe98b283dfec7c2e88d6a2b8ac455e4bec8d7b985b928b0 16 | assets/assets/images/handshake.png,1664637518506,c2c805f5da7423cbca7a0cd94838f9e7dc33a7f3062eeebf6e1cf13164de6184 17 | assets/assets/images/icon_community.png,1664637518506,c07fbfb180de1bcbf37bc402016ce0d8e7a56eae879733bbac87e4a56ca39e55 18 | assets/assets/images/ocy_logo.png,1664637518506,5380a6fc11aee558934d43d0fd8e52eb2f7284cc611792300213cd34faf67113 19 | assets/assets/images/teams.jpg,1664637518516,01f4e76d7fdd85086f764aa8f35fe8356d3e8251b513259859bb32cadefe49c5 20 | assets/assets/images/welcome.jpg,1664637518516,776e69235064e4e884b50dda0c98fa94dd6c25743cf92b838e9e6a17b59ecf33 21 | assets/fonts/MaterialIcons-Regular.otf,1652601154936,6c5b450bbaa24bf30f1a1c111fe2be1e9c2cb23dde6fa9ee8b3609e812302aed 22 | assets/packages/fluttertoast/assets/toastify.css,1648229989936,6afc6f35b72ca06962c0b9197750a2af6334c905331f080d8047b437ffa170b1 23 | assets/packages/fluttertoast/assets/toastify.js,1648229989951,76b60b9795e3b1093a16956ede93215d4315c157c3fbc99de1483999c081eb89 24 | assets/packages/font_awesome_flutter/lib/fonts/fa-brands-400.ttf,1664858649863,7bbb66c28cb081bed5962213758552bf2243705f1d8fa6bb6c80fd43277f39f9 25 | assets/packages/font_awesome_flutter/lib/fonts/fa-regular-400.ttf,1664858649832,171dd2d143a4a3b602c3de48f0eb2d2090a870ca1f6368991264317aa6f83870 26 | assets/packages/font_awesome_flutter/lib/fonts/fa-solid-900.ttf,1664858649816,2f92675a0fa593f31c5e1e841f341f2a8c35e173dcb834732718ba59bfebcfcd 27 | assets/packages/line_icons/lib/assets/fonts/LineIcons.ttf,1642488512952,afa977305511f17872e9c199cc334e881c22f387b9e0b3cf552347a2a1eabcee 28 | canvaskit/canvaskit.js,1671250576441,1c5e4be41a8a2901d8c9ae4edb5c2bd26c5c4d0564d732a3ce2bef7c6c27bcb0 29 | canvaskit/canvaskit.wasm,1671250576472,5ead4a7a5f1445e19dbf4515ce48c88ad7070b05c4c318e8a73f83917862aa16 30 | canvaskit/profiling/canvaskit.js,1671250576473,15d13a02cb0d513cda2f2a2b63df45ad9ebb843723e1380386b016360ffc9ba0 31 | canvaskit/profiling/canvaskit.wasm,1671250576512,92eb89423488999d48294283d3905d1040b96088d7e3c243bf109dbd1bb29ee0 32 | icons/apple-touch-icon.png,1664637518612,85bdb54cb9e9429b809ffca176de83fd0c8229d6779af9ed8d015f809411c89d 33 | icons/icon-192.png,1664637518612,e581fe7427d8dd4acd45f0717c401c358ef593abd7dc0c24a97601a93a7203b6 34 | icons/icon-384.png,1664637518612,9f64c5bf089ebf7aea6ac359e1db8a6f435b6bdbf107066906984e90caf2a7ee 35 | icons/icon-maskable-192.png,1664637518612,e581fe7427d8dd4acd45f0717c401c358ef593abd7dc0c24a97601a93a7203b6 36 | icons/icon-maskable-512.png,1664637518612,a9b693791ae3bebed1aedb59a6a209cb3508d86702c60c5ccf023db50656917c 37 | icons/mstile-150x150.png,1664637518612,a38c6ed68873099e3e5e6f7e47bdb479e859b9b22c020d7522e8dfb5fd0e00f6 38 | icons/safari-pinned-tab.svg,1664637518612,4cb0bab46f560d040ebf5403a3b37a2f1b8239d338c3a726f82f7967aee325db 39 | assets/AssetManifest.json,1672721835245,f4bf6ae3057f7896d3a8242d0261053a4724e391fec2410c2d5189af42f265e3 40 | flutter_service_worker.js,1672721838859,169444effc55f098785ab1827adbc872708886bc72d32a5075ff724eefdf24cc 41 | index.html,1672721835781,df5055925b9136a559320c9c8cf5c4890e6881cb62105ca2c671721f5a5673df 42 | assets/FontManifest.json,1672721835245,e2645b56b34950c0c501adcbeb9c1bec9bcc5ef3bf4509e6c6025c2b3eb47fc4 43 | version.json,1672721834819,24d176ec89ce89a0d343dda21102bca7428dd459838bd7f8d9690aadbe52d7da 44 | assets/shaders/ink_sparkle.frag,1672721835592,1c6829fee2ec1eeba159adb8964740cecaf55dbe614560a997b0c9e5a5f6844f 45 | assets/NOTICES,1672721835245,2e9f207e09996c37b1fab00293ae4618fc8c00aae9209c0412c62c2d8e8bee78 46 | main.dart.js,1672721831139,1b00410ff95aae0ab27ac6e978ab5b60565ec386e86cefc4a088b2eb7f942a10 47 | -------------------------------------------------------------------------------- /lib/configs/config.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 3 | import 'package:line_icons/line_icons.dart'; 4 | import 'package:ocyclient/models/localization/language.dart'; 5 | 6 | /// {@category Configs} 7 | class Config { 8 | static final Map _routeNames = { 9 | "home": "/home", 10 | // "Community": "/community", 11 | "about_us": "/about_us", 12 | "teams": "/teams", 13 | // "Milestones": "/milestones", 14 | }; 15 | 16 | static Map get routeNames => _routeNames; 17 | 18 | static final List _appDrawerIcons = [ 19 | LineIcons.home, 20 | LineIcons.globe, 21 | LineIcons.question, 22 | LineIcons.peopleCarry, 23 | Icons.emoji_events_outlined, 24 | Icons.logout_sharp, 25 | ]; 26 | 27 | static final List _selectedAppDrawerIcons = [ 28 | FontAwesomeIcons.house, 29 | FontAwesomeIcons.earthAmericas, 30 | FontAwesomeIcons.question, 31 | FontAwesomeIcons.peopleCarryBox, 32 | FontAwesomeIcons.trophy, 33 | Icons.logout, 34 | ]; 35 | 36 | static List get appDrawerIcons => _appDrawerIcons; 37 | 38 | static List get selectedAppDrawerIcons => _selectedAppDrawerIcons; 39 | 40 | ///GitHub Configs 41 | static const String clientId = "ba4e3c2ad6622ba3b12c"; 42 | static const String clientSecret = "079b49d4b5ba6e84ad7ec4f4d4e90163c35c18ad"; 43 | 44 | static const String redirectUrl = 45 | "https://opencodeyard.firebaseapp.com/__/auth/handler"; 46 | 47 | ///Shared Preferences Keys 48 | static const String prefIsLoggedIn = "is_logged_in"; 49 | static const String prefName = "name"; 50 | static const String prefEmail = "email"; 51 | static const String prefProfilePicUrl = "profile_pic_url"; 52 | static const String prefUid = "uid"; 53 | static const String prefGithubAccessToken = "user_github_access_token"; 54 | static const String prefLoginProvidersConnected = "login_providers"; 55 | static const String prefSkills = "skills"; 56 | static const String prefPhone = "user_phone"; 57 | static const String prefGender = "user_gender"; 58 | static const String prefDOB = "user_dob"; 59 | static const String prefBio = "user_bio"; 60 | static const String prefEmploymentStatus = "employment_status"; 61 | static const String prefLocality = "locality"; 62 | 63 | ///Routes that should not be accessible to authenticated users 64 | static const List authenticatedPreventAccessRoutes = ["/auth"]; 65 | 66 | ///Routes that should not be accessible to unauthenticated users 67 | static const List unauthenticatedPreventAccessRoutes = [ 68 | "/profile", 69 | "/editProfile" 70 | ]; 71 | 72 | static const appVersion = "0.3.1-alpha"; 73 | 74 | ///Firestore Collection Names 75 | static const fsUser = "Users"; 76 | 77 | ///Firestore field Names 78 | static const userUID = "uid"; 79 | static const userName = "name"; 80 | static const userEmail = "email"; 81 | static const userProfilePic = "profilePic"; 82 | static const userLoginProviders = "loginProviders"; 83 | static const userGithubAccessToken = "accessTokenGithub"; 84 | static const userSkills = "skills"; 85 | static const userBio = "bio"; 86 | static const userGender = "gender"; 87 | static const userDob = "dob"; 88 | static const userEmploymentStatus = "employment"; 89 | static const userLocality = "locality"; 90 | static const userPhone = "phone"; 91 | 92 | ///Github api 93 | static const ghOrganisationName = "OpenCodeyard"; 94 | static const ghRootUrl = "https://api.github.com/"; 95 | static const ghOrganisationsApi = "orgs"; 96 | static const ghReposApi = "repos"; 97 | static const ghUserApi = "user"; 98 | 99 | static const Color themeColor = Colors.deepPurple; 100 | 101 | static const String communityLogoPath = "assets/images/ocy_logo.png"; 102 | 103 | ///Env names 104 | static const String envGhAccessToken = "github_access_token"; 105 | 106 | ///Social 107 | static const String linkedInUrl = 108 | "https://www.linkedin.com/company/opencodeyard"; 109 | static const String ghUrl = "https://github.com/OpenCodeyard"; 110 | static const String telegramUrl = "https://telegram.me/Open_Codeyard"; 111 | 112 | static const List weAre = [ 113 | "Coders 💻", 114 | "Students 🧑‍🎓", 115 | "Professionals 💼", 116 | "Dreamers 😴", 117 | "builders ⚒️", 118 | "Innovators 💡", 119 | "Gamers 🎮", 120 | "Hackers 🕶️", 121 | "Brain-Stormers 💡", 122 | "Techies 🧑‍💻", 123 | "Singers 👨‍🎤", 124 | "Dancers 🕺", 125 | "Open Codeyard ♥️", 126 | ]; 127 | 128 | static const List weAreColors = [ 129 | Color(0xfffa5457), 130 | Color(0xff01b4bc), 131 | Color(0xffe3c515), 132 | Color(0xffa59cd3), 133 | Color(0xff4b2d9f), 134 | ]; 135 | 136 | static List languageList = [ 137 | Language("English", "US", "en"), 138 | Language("বাংলা", "IN", "bn"), 139 | Language("हिंदी", "IN", "hn"), 140 | Language("मराठी","IN","mt") 141 | ]; 142 | } 143 | -------------------------------------------------------------------------------- /web/icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.14, written by Peter Selinger 2001-2017 9 | 10 | 12 | 28 | 43 | 54 | 57 | 59 | 61 | 63 | 69 | 75 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | support@opencodeyard.tech. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /lib/widgets/Utils/custom_inputfields.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ocyclient/configs/config.dart'; 3 | 4 | buildInputFieldThemColor( 5 | String label, 6 | IconData icon, 7 | TextInputType type, 8 | TextEditingController controller, 9 | BuildContext context, 10 | bool isLast, 11 | FocusNode node, 12 | FocusNode? nextNode, 13 | bool isEnabled, 14 | String? Function(String?)? validator, { 15 | Function(String)? onChanged, 16 | }) { 17 | return Column( 18 | children: [ 19 | const SizedBox( 20 | height: 20, 21 | ), 22 | TextFormField( 23 | controller: controller, 24 | textInputAction: isLast ? TextInputAction.done : TextInputAction.next, 25 | focusNode: node, 26 | enabled: isEnabled, 27 | onFieldSubmitted: (s) { 28 | if (nextNode != null) { 29 | nextNode.requestFocus(); 30 | } else if (isLast) { 31 | FocusScope.of(context).unfocus(); 32 | } else { 33 | FocusScope.of(context).nextFocus(); 34 | } 35 | }, 36 | onChanged: onChanged, 37 | validator: validator, 38 | autofocus: false, 39 | style: const TextStyle( 40 | color: Colors.black, 41 | ), 42 | keyboardType: type, 43 | cursorColor: Config.themeColor, 44 | decoration: InputDecoration( 45 | labelText: label, 46 | labelStyle: const TextStyle(color: Colors.black), 47 | prefixIcon: Icon( 48 | icon, 49 | size: 18, 50 | color: Colors.black, 51 | ), 52 | filled: true, 53 | border: OutlineInputBorder( 54 | borderRadius: BorderRadius.circular(4), 55 | borderSide: const BorderSide( 56 | width: 1, 57 | color: Colors.grey, 58 | style: BorderStyle.solid, 59 | ), 60 | ), 61 | enabledBorder: OutlineInputBorder( 62 | borderRadius: BorderRadius.circular(4), 63 | borderSide: const BorderSide( 64 | width: 2, 65 | color: Colors.black, 66 | style: BorderStyle.solid, 67 | ), 68 | ), 69 | focusedBorder: OutlineInputBorder( 70 | borderRadius: BorderRadius.circular(4), 71 | borderSide: const BorderSide( 72 | width: 2, 73 | color: Config.themeColor, 74 | style: BorderStyle.solid, 75 | ), 76 | ), 77 | disabledBorder: OutlineInputBorder( 78 | borderRadius: BorderRadius.circular(4), 79 | borderSide: const BorderSide( 80 | width: 2, 81 | color: Colors.blueGrey, 82 | style: BorderStyle.solid, 83 | ), 84 | ), 85 | ), 86 | ) 87 | ], 88 | ); 89 | } 90 | 91 | buildDescInputFieldThemColor( 92 | String label, 93 | IconData icon, 94 | TextInputType type, 95 | TextEditingController controller, 96 | BuildContext context, 97 | FocusNode node, 98 | FocusNode? nextNode, 99 | bool isEnabled, 100 | bool isLast, { 101 | Function(String)? onChanged, 102 | int maxLength = 300, 103 | }) { 104 | return Column( 105 | children: [ 106 | const SizedBox( 107 | height: 20, 108 | ), 109 | TextFormField( 110 | controller: controller, 111 | autocorrect: true, 112 | keyboardType: type, 113 | autofocus: false, 114 | maxLines: null, 115 | style: const TextStyle( 116 | color: Colors.black, 117 | ), 118 | textInputAction: TextInputAction.newline, 119 | onFieldSubmitted: (s) { 120 | if (nextNode != null) { 121 | FocusScope.of(context).requestFocus(nextNode); 122 | } else if (isLast) { 123 | FocusScope.of(context).unfocus(); 124 | } else { 125 | FocusScope.of(context).nextFocus(); 126 | } 127 | }, 128 | onChanged: onChanged, 129 | focusNode: node, 130 | enabled: isEnabled, 131 | cursorColor: Config.themeColor, 132 | maxLength: maxLength, 133 | decoration: InputDecoration( 134 | labelText: label, 135 | labelStyle: const TextStyle(color: Colors.black), 136 | prefixIcon: Icon( 137 | icon, 138 | size: 18, 139 | color: Colors.black, 140 | ), 141 | filled: true, 142 | border: OutlineInputBorder( 143 | borderRadius: BorderRadius.circular(4), 144 | borderSide: const BorderSide( 145 | width: 1, 146 | color: Colors.grey, 147 | style: BorderStyle.solid, 148 | ), 149 | ), 150 | enabledBorder: OutlineInputBorder( 151 | borderRadius: BorderRadius.circular(4), 152 | borderSide: const BorderSide( 153 | width: 2, 154 | color: Colors.black, 155 | style: BorderStyle.solid, 156 | ), 157 | ), 158 | focusedBorder: OutlineInputBorder( 159 | borderRadius: BorderRadius.circular(4), 160 | borderSide: const BorderSide( 161 | width: 2, 162 | color: Config.themeColor, 163 | style: BorderStyle.solid, 164 | ), 165 | ), 166 | disabledBorder: OutlineInputBorder( 167 | borderRadius: BorderRadius.circular(4), 168 | borderSide: const BorderSide( 169 | width: 2, 170 | color: Colors.blueGrey, 171 | style: BorderStyle.solid, 172 | ), 173 | ), 174 | ), 175 | ) 176 | ], 177 | ); 178 | } 179 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | 5 |

6 | 7 |
8 | 9 | # OCY Client [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.0-4baaaa.svg)](code_of_conduct.md) 10 | 11 | This repo contains source code for the official Flutter Client of Open CodeYard 12 | 13 | A higly configurable community website template built using Flutter 14 | 15 | 16 |
17 | Table of Contents 18 |
    19 |
    20 |
  1. 21 | About The Project 22 | 28 |
  2. 29 |
  3. 30 | Getting Started 31 | 35 |
  4. 36 | 37 |
  5. Contact
  6. 38 | 39 |
40 |
41 | 42 |

43 | 44 | ## About the project 45 | 46 |   :construction:**Actively under development**:construction: 47 | 48 | - ### Built With 49 | 50 | [![Flutter][flutter-image]][flutter-url]   [![Firebase][firebase-image]][firebase-url] 51 | 52 | -
53 | Screenshots :iphone: 54 |
55 | 56 | Coming Soon 57 | 58 |
59 | 60 | - ####

Documentation :notebook:

61 | 62 | * This project uses [Effective Dart Principles]() for documentation 63 | * Run `dart doc .` from root of project directory to generate documentation webpage. 64 | 65 | - #### Features 66 | 67 | * Self Hosted using Firebase 68 | * FCM for notification (Coming soon) 69 | * Built using [Provider Architecture](https://pub.dev/packages/provider) for clean state management 70 | * Google and GitHub login support for User Authentication 71 | * Custom user management logic using Firestore 72 | * Data caching for optimised network calls 73 | * Profile Screen 74 | * Fluid animations 75 | * Modern, Material UI (we all love this!) 76 | * Heavyily documented code (who doesn't like clean code) 77 | 78 |

(back to top)

79 | 80 | ## Getting Started 81 | 82 | - This project depends heavily on firebase. A few resources to get you started if this is your first Firebase project: 83 | 84 | * [Lab: Firebase for Flutter](https://firebase.google.com/codelabs/firebase-get-to-know-flutter#0) 85 | * [FlutterFire Plugins](https://firebase.flutter.dev/) 86 | 87 | - A few resources to get you started if this is your first Flutter project: 88 | 89 | * [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) 90 | * [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) 91 | 92 |   For help getting started with Flutter development, view the 93 | [online documentation](https://docs.flutter.dev/), which offers tutorials, 94 | samples, guidance on mobile development, and a full API reference. 95 | 96 | - #### Project Setup 97 | 98 | * Flutter App: 99 | * [Install Flutter](https://docs.flutter.dev/get-started/install) 100 | * [Setting up your ide](https://flutter.io/ide-setup/) 101 | * Fork and clone this repository. 102 | * cd into `ocyclient` directory. 103 | * Run `flutter clean` command. 104 | * Run `flutter pub get` command. 105 | * Run `flutter run` command. 106 | 107 | * Firebase: 108 | * Create a firebase project 109 | * Add android app with your package name in firebase console. 110 | * Enable Google Auth from `Authentication` menu in Firebase. 111 | * Create a file named env and store github_access_token in it (See [env_example.txt](https://github.com/OpenCodeyard/ocyclient/blob/dev/env_example.txt) file in project root for example). Check [this link](https://docs.github.com/en/enterprise-server@3.4/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) to see how to create a github access token. 112 | * Generate `SHA-1 key hash` for your debug keystore from your pc. This needs to be added to `SHA certificate fingerprints` section under your android app in `Firebase project settings`. Without this step **Google login** won't work. 113 | * Enable ***Cloud Firestore*** 114 | * Recommended rules for Firestore 115 | 116 | ```JS 117 | rules_version = '2'; 118 | service cloud.firestore { 119 | match /databases/{database}/documents { 120 | match /{document=**} { 121 | allow read, write: if 122 | request.auth != null; 123 | } 124 | } 125 | } 126 | ``` 127 | * Enable ***Cloud Storage*** 128 | * Download `google_services.json` from `Console` -> `Project Settings`. File is present in app section. SDK instructions found in the same page 129 | * (Optional) Enable ***Cloud Messaging*** from Firebase Console if you wan't notifications to work in your app 130 | * (Optional) If released to play store get `SHA-1 key hash` from playstore and upload them to firebase, otherwise google sign in won't work in play store app. 131 | 132 | * #### Contribution 133 | 134 | ##### Check out our awesome contributors:
135 | 136 | 137 | 138 | 139 | Made with [contributors-img](https://contrib.rocks). 140 |
141 | 142 | Check [Contributing.md](https://github.com/OpenCodeyard/ocyclient/blob/dev/CONTRIBUTING.md) for guidelines on contributing to this repo. 143 | 144 |

(back to top)

145 | 146 | ## Contact Us 147 | 148 |   If you have a question, please feel free to contact us through [email](mailto:support@opencodeyard.tech) or our [telegram community channel](https://telegram.me/Open_Codeyard). 149 | 150 |



151 | 152 |

153 | Made with ❤️ by Open Codeyard 154 |

155 | 156 |

157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | [flutter-image]: https://img.shields.io/badge/Flutter-%2302569B.svg?style=plastic&logo=Flutter&logoColor=5cc8f8 167 | [flutter-url]: https://flutter.dev 168 | [firebase-image]: https://img.shields.io/badge/firebase-%23039BE5.svg?style=plastic&logo=firebase 169 | [firebase-url]: https://firebase.com/ 170 | -------------------------------------------------------------------------------- /lib/widgets/Home/sub_pages/footer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 3 | import 'package:ocyclient/blocs/navigation_bloc.dart'; 4 | import 'package:ocyclient/configs/config.dart'; 5 | import 'package:ocyclient/widgets/Utils/common_widgets.dart'; 6 | import 'package:provider/provider.dart'; 7 | import 'package:url_launcher/url_launcher_string.dart'; 8 | 9 | class Footer extends StatelessWidget { 10 | const Footer({Key? key}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | Size size = MediaQuery.of(context).size; 15 | 16 | NavigationBloc nb = Provider.of(context); 17 | 18 | return Container( 19 | color: const Color(0xff152839), 20 | height: size.width <= 700 ? null : 300, 21 | padding: const EdgeInsets.all(10), 22 | child: Column( 23 | crossAxisAlignment: CrossAxisAlignment.start, 24 | children: [ 25 | const SizedBox( 26 | height: 40, 27 | ), 28 | size.width > 700 29 | ? Row( 30 | crossAxisAlignment: CrossAxisAlignment.start, 31 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 32 | children: [ 33 | about(size), 34 | contactUs(size), 35 | legal(size, nb), 36 | ], 37 | ) 38 | : Column( 39 | mainAxisAlignment: MainAxisAlignment.center, 40 | children: [ 41 | about(size), 42 | const SizedBox( 43 | height: 50, 44 | ), 45 | Row( 46 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 47 | children: [ 48 | contactUs(size), 49 | legal(size, nb), 50 | ], 51 | ), 52 | const SizedBox( 53 | height: 30, 54 | ), 55 | ], 56 | ), 57 | ], 58 | ), 59 | ); 60 | } 61 | 62 | Widget contactUs(Size size) { 63 | return Column( 64 | crossAxisAlignment: CrossAxisAlignment.start, 65 | children: [ 66 | const Text( 67 | "Contact Us", 68 | style: TextStyle( 69 | color: Colors.white54, 70 | fontFamily: "PublicSans", 71 | ), 72 | ), 73 | const SizedBox( 74 | height: 20, 75 | ), 76 | getIconButton( 77 | title: "Email", 78 | func: () { 79 | launchUrlString("mailto:support@opencodeyard.tech"); 80 | }, 81 | icon: FontAwesomeIcons.envelope, 82 | ), 83 | const SizedBox( 84 | height: 20, 85 | ), 86 | getIconButton( 87 | title: "FAQ", 88 | func: () { 89 | // nb.toRoute("/licenses"); 90 | }, 91 | icon: FontAwesomeIcons.question, 92 | ), 93 | const SizedBox( 94 | height: 20, 95 | ), 96 | getIconButton( 97 | title: "Support", 98 | func: () { 99 | // nb.toRoute("/licenses"); 100 | }, 101 | icon: FontAwesomeIcons.headset, 102 | ), 103 | ], 104 | ); 105 | } 106 | 107 | Widget legal(Size size, NavigationBloc nb) { 108 | return Column( 109 | crossAxisAlignment: CrossAxisAlignment.start, 110 | children: [ 111 | const Text( 112 | "Legal", 113 | style: TextStyle( 114 | color: Colors.white54, 115 | fontFamily: "PublicSans", 116 | ), 117 | ), 118 | const SizedBox( 119 | height: 20, 120 | ), 121 | getIconButton( 122 | title: "Terms", 123 | func: () { 124 | // nb.toRoute("/licenses"); 125 | }, 126 | icon: FontAwesomeIcons.scaleBalanced, 127 | ), 128 | const SizedBox( 129 | height: 20, 130 | ), 131 | getIconButton( 132 | title: "Privacy", 133 | func: () { 134 | // nb.toRoute("/licenses"); 135 | }, 136 | icon: FontAwesomeIcons.userShield, 137 | ), 138 | const SizedBox( 139 | height: 20, 140 | ), 141 | getIconButton( 142 | title: "Licenses", 143 | func: () { 144 | nb.toRoute("/licenses"); 145 | }, 146 | icon: FontAwesomeIcons.fileInvoice, 147 | ), 148 | ], 149 | ); 150 | } 151 | 152 | Widget about(Size size) { 153 | return Column( 154 | children: [ 155 | RichText( 156 | text: TextSpan( 157 | text: "{", 158 | style: TextStyle( 159 | fontSize: size.width < 1100 && size.width > 900 ? 14 : 20, 160 | fontWeight: FontWeight.bold, 161 | color: Colors.white, 162 | fontFamily: "PublicSans", 163 | ), 164 | children: [ 165 | TextSpan( 166 | text: " Open ", 167 | style: TextStyle( 168 | fontSize: size.width < 1100 && size.width > 900 ? 14 : 20, 169 | fontWeight: FontWeight.normal, 170 | color: Colors.white38, 171 | ), 172 | ), 173 | TextSpan( 174 | text: "Codeyard ", 175 | style: TextStyle( 176 | fontSize: size.width < 1100 && size.width > 900 ? 14 : 20, 177 | fontWeight: FontWeight.bold, 178 | ), 179 | ), 180 | TextSpan( 181 | text: "} ;", 182 | style: TextStyle( 183 | fontSize: size.width < 1100 && size.width > 900 ? 14 : 20, 184 | fontWeight: FontWeight.bold, 185 | ), 186 | ), 187 | ], 188 | ), 189 | ), 190 | const SizedBox( 191 | height: 40, 192 | ), 193 | Row( 194 | mainAxisAlignment: MainAxisAlignment.center, 195 | children: [ 196 | getFooterSocialButton( 197 | FontAwesomeIcons.github, 198 | link: Config.ghUrl, 199 | ), 200 | getFooterSocialButton( 201 | FontAwesomeIcons.linkedinIn, 202 | link: Config.linkedInUrl, 203 | ), 204 | getFooterSocialButton( 205 | FontAwesomeIcons.discord, 206 | ), 207 | getFooterSocialButton( 208 | FontAwesomeIcons.telegram, 209 | link: Config.telegramUrl, 210 | ), 211 | ], 212 | ), 213 | const SizedBox( 214 | height: 40, 215 | ), 216 | const Text( 217 | "Engineered with ❤️ by\nOpen Codeyard", 218 | textAlign: TextAlign.center, 219 | style: TextStyle( 220 | height: 1.6, 221 | color: Colors.white, 222 | fontWeight: FontWeight.bold, 223 | fontFamily: "PublicSans", 224 | fontSize: 19, 225 | ), 226 | ), 227 | ], 228 | ); 229 | } 230 | 231 | List getFooterWidgets(Size size, NavigationBloc nb) { 232 | return [ 233 | about(size), 234 | contactUs(size), 235 | legal(size, nb), 236 | ]; 237 | } 238 | 239 | } 240 | -------------------------------------------------------------------------------- /lib/widgets/Profile/edit_profile.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 3 | import 'package:ocyclient/blocs/auth_bloc.dart'; 4 | import 'package:ocyclient/blocs/edit_profile_bloc.dart'; 5 | import 'package:ocyclient/blocs/navigation_bloc.dart'; 6 | import 'package:ocyclient/widgets/Profile/sub_pages/edit_personal.dart'; 7 | import 'package:ocyclient/widgets/Utils/common_widgets.dart'; 8 | import 'package:ocyclient/widgets/Utils/ocy_scaffold.dart'; 9 | import 'package:provider/provider.dart'; 10 | 11 | class EditProfilePage extends StatefulWidget { 12 | const EditProfilePage({Key? key}) : super(key: key); 13 | 14 | @override 15 | EditProfilePageState createState() => EditProfilePageState(); 16 | } 17 | 18 | class EditProfilePageState extends State { 19 | ///TODO cover attribution Background vector created by freepik - www.freepik.com 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | Size size = MediaQuery.of(context).size; 24 | 25 | EditProfileBloc epb = Provider.of(context); 26 | AuthenticationBloc ab = Provider.of(context); 27 | NavigationBloc nb = Provider.of(context); 28 | 29 | return OcyScaffold( 30 | body: SizedBox( 31 | height: size.height - 70, 32 | child: size.width < 1000 33 | ? SingleChildScrollView( 34 | physics: const BouncingScrollPhysics(), 35 | child: Column( 36 | children: [ 37 | const SizedBox( 38 | height: 20, 39 | ), 40 | Padding( 41 | padding: const EdgeInsets.symmetric(horizontal: 8.0), 42 | child: Card( 43 | elevation: 10, 44 | shape: RoundedRectangleBorder( 45 | borderRadius: BorderRadius.circular(15), 46 | ), 47 | child: SingleChildScrollView( 48 | scrollDirection: Axis.horizontal, 49 | physics: const BouncingScrollPhysics(), 50 | padding: const EdgeInsets.symmetric( 51 | horizontal: 5, 52 | vertical: 10, 53 | ), 54 | child: Row( 55 | mainAxisAlignment: MainAxisAlignment.center, 56 | children: getEditProfileMenu(size, epb, ab, nb), 57 | ), 58 | ), 59 | ), 60 | ), 61 | const PersonalTab(), 62 | ], 63 | ), 64 | ) 65 | : Row( 66 | children: [ 67 | Card( 68 | elevation: 10, 69 | margin: EdgeInsets.zero, 70 | child: SizedBox( 71 | height: size.height, 72 | width: 230, 73 | child: SingleChildScrollView( 74 | physics: const BouncingScrollPhysics(), 75 | padding: const EdgeInsets.symmetric( 76 | horizontal: 25, 77 | vertical: 10, 78 | ), 79 | child: Column( 80 | children: getEditProfileMenu(size, epb, ab, nb), 81 | ), 82 | ), 83 | ), 84 | ), 85 | const VerticalDivider( 86 | width: 1, 87 | color: Colors.black12, 88 | ), 89 | const PersonalTab(), 90 | const VerticalDivider( 91 | width: 1, 92 | color: Colors.black12, 93 | ), 94 | if (size.width >= 1500) 95 | const SizedBox(), 96 | ], 97 | ), 98 | ), 99 | ); 100 | } 101 | 102 | List getEditProfileMenu( 103 | Size size, 104 | EditProfileBloc epb, 105 | AuthenticationBloc ab, 106 | NavigationBloc nb, 107 | ) { 108 | bool isHorizontal = false; 109 | if (size.width < 1000) { 110 | isHorizontal = true; 111 | } 112 | return [ 113 | getCustomSizedBoxForMenu(isHorizontal), 114 | if (!isHorizontal) ...[ 115 | Image.asset( 116 | "assets/images/ocy_logo.png", 117 | width: 100, 118 | height: 100, 119 | ), 120 | const SizedBox( 121 | height: 30, 122 | ), 123 | ], 124 | getSideMenuButton( 125 | epb, 126 | "Personal", 127 | FontAwesomeIcons.userLarge, 128 | 0, 129 | isHorizontal, 130 | ), 131 | getCustomSizedBoxForMenu(isHorizontal), 132 | getSideMenuButton( 133 | epb, 134 | "Education", 135 | FontAwesomeIcons.userGraduate, 136 | 1, 137 | isHorizontal, 138 | ), 139 | getCustomSizedBoxForMenu(isHorizontal), 140 | getSideMenuButton( 141 | epb, 142 | "Experience", 143 | FontAwesomeIcons.briefcase, 144 | 2, 145 | isHorizontal, 146 | ), 147 | getCustomSizedBoxForMenu(isHorizontal), 148 | ]; 149 | } 150 | 151 | Widget getSideMenuButton( 152 | EditProfileBloc pb, 153 | String title, 154 | IconData icon, 155 | int index, 156 | bool isHorizontal, { 157 | AuthenticationBloc? authBloc, 158 | NavigationBloc? navBloc, 159 | }) { 160 | return MouseRegion( 161 | cursor: SystemMouseCursors.click, 162 | child: GestureDetector( 163 | onTap: () { 164 | pb.setCurrentSelectedItem(index); 165 | if (index == 3) { 166 | authBloc?.signOut(context, navBloc!); 167 | } 168 | }, 169 | child: AnimatedContainer( 170 | padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15), 171 | decoration: BoxDecoration( 172 | color: pb.currentSelectedMenuItem == index 173 | ? const Color(0x73c6dbec) 174 | : Colors.white, 175 | borderRadius: BorderRadius.circular(10), 176 | ), 177 | duration: const Duration(milliseconds: 500), 178 | curve: Curves.fastOutSlowIn, 179 | child: SizedBox( 180 | child: Row( 181 | children: [ 182 | Text( 183 | title, 184 | style: TextStyle( 185 | color: pb.currentSelectedMenuItem == index 186 | ? Colors.black 187 | : Colors.grey, 188 | fontWeight: pb.currentSelectedMenuItem == index 189 | ? FontWeight.bold 190 | : FontWeight.normal, 191 | fontSize: 14, 192 | fontFamily: "PublicSans"), 193 | ), 194 | if (isHorizontal) 195 | const SizedBox( 196 | width: 20, 197 | ) 198 | else 199 | const Spacer(), 200 | getIconForButton(icon), 201 | if (isHorizontal) 202 | const SizedBox( 203 | width: 10, 204 | ) 205 | ], 206 | ), 207 | ), 208 | ), 209 | ), 210 | ); 211 | } 212 | 213 | Widget getCustomSizedBoxForMenu(bool isHorizontal) { 214 | return isHorizontal 215 | ? const SizedBox( 216 | width: 30, 217 | ) 218 | : const SizedBox( 219 | height: 30, 220 | ); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | Open Codeyard 48 | 49 | 51 | 52 | 110 | 111 | 112 | 113 | 114 | 115 |
116 | Open Codeyard 118 |
119 |
120 |
121 |
122 |
123 | 124 | 125 | 130 | 131 | 132 | 133 | 134 | 150 | 151 | 154 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_core/firebase_core.dart'; 2 | import 'package:flutter/foundation.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/services.dart'; 5 | import 'package:flutter_dotenv/flutter_dotenv.dart'; 6 | import 'package:flutter_localizations/flutter_localizations.dart'; 7 | import 'package:flutter_web_plugins/flutter_web_plugins.dart'; 8 | import 'package:get/get_navigation/src/root/get_material_app.dart'; 9 | import 'package:get/get_navigation/src/routes/get_route.dart'; 10 | import 'package:ocyclient/blocs/auth_bloc.dart'; 11 | import 'package:ocyclient/blocs/community_bloc.dart'; 12 | import 'package:ocyclient/blocs/edit_profile_bloc.dart'; 13 | import 'package:ocyclient/blocs/locale_bloc.dart'; 14 | import 'package:ocyclient/blocs/navigation_bloc.dart'; 15 | import 'package:ocyclient/blocs/profile_bloc.dart'; 16 | import 'package:ocyclient/blocs/projects_bloc.dart'; 17 | import 'package:ocyclient/blocs/teams_bloc.dart'; 18 | import 'package:ocyclient/configs/config.dart'; 19 | import 'package:ocyclient/utils/app_translations.dart'; 20 | import 'package:ocyclient/widgets/AboutUs/about_us.dart'; 21 | import 'package:ocyclient/widgets/Auth/login_signup.dart'; 22 | import 'package:ocyclient/widgets/Community/community.dart'; 23 | import 'package:ocyclient/widgets/Home/home.dart'; 24 | import 'package:ocyclient/widgets/Milestones/milestones.dart'; 25 | import 'package:ocyclient/widgets/Profile/edit_profile.dart'; 26 | import 'package:ocyclient/widgets/Profile/profile.dart'; 27 | import 'package:ocyclient/widgets/Teams/teams.dart'; 28 | import 'package:provider/provider.dart'; 29 | import 'package:shared_preferences/shared_preferences.dart'; 30 | import 'firebase_options.dart'; 31 | 32 | void main() async { 33 | WidgetsFlutterBinding.ensureInitialized(); 34 | await configureApp(); 35 | runApp(OCYApp()); 36 | } 37 | 38 | void enableEdgeToEdge({bool enable = true}) { 39 | ///Necessary for edge to edge 40 | SystemChrome.setSystemUIOverlayStyle( 41 | const SystemUiOverlayStyle(systemNavigationBarColor: Colors.white), 42 | ); 43 | SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); 44 | } 45 | 46 | Future configureApp() async { 47 | setUrlStrategy(PathUrlStrategy()); 48 | await dotenv.load(fileName: "env"); 49 | if (kIsWeb || Firebase.apps.isEmpty) { 50 | await Firebase.initializeApp( 51 | options: DefaultFirebaseOptions.currentPlatform); 52 | } 53 | SharedPreferences sp = await SharedPreferences.getInstance(); 54 | 55 | bool isLoggedIn = sp.getBool(Config.prefIsLoggedIn) ?? false; 56 | 57 | final String defaultRouteName = 58 | WidgetsBinding.instance.window.defaultRouteName; 59 | 60 | bool allowAuthenticated = 61 | Config.authenticatedPreventAccessRoutes.contains(defaultRouteName); 62 | bool allowUnauthenticated = 63 | Config.unauthenticatedPreventAccessRoutes.contains(defaultRouteName); 64 | if (isLoggedIn && allowAuthenticated) { 65 | SystemNavigator.routeInformationUpdated(location: '/home', replace: true); 66 | } 67 | if (!isLoggedIn && allowUnauthenticated) { 68 | SystemNavigator.routeInformationUpdated(location: '/home', replace: true); 69 | } 70 | 71 | enableEdgeToEdge(); 72 | } 73 | 74 | class OCYApp extends StatelessWidget { 75 | OCYApp({Key? key}) : super(key: key); 76 | 77 | final GlobalKey navigatorKey = GlobalKey(); 78 | 79 | @override 80 | Widget build(BuildContext context) { 81 | return MultiProvider( 82 | providers: [ 83 | ChangeNotifierProvider( 84 | create: (context) => NavigationBloc(navigatorKey), 85 | ), 86 | ChangeNotifierProvider( 87 | create: (context) => AuthenticationBloc(), 88 | ), 89 | ChangeNotifierProvider( 90 | create: (context) => ProfileBloc(), 91 | ), 92 | ChangeNotifierProvider( 93 | create: (context) => EditProfileBloc(), 94 | ), 95 | ChangeNotifierProvider( 96 | create: (context) => ProjectsBloc(), 97 | ), 98 | ChangeNotifierProvider( 99 | create: (context) => CommunityBloc(), 100 | ), 101 | ChangeNotifierProvider( 102 | create: (context) => TeamsBloc(), 103 | ), 104 | ChangeNotifierProvider( 105 | create: (context) => LocaleBLoc(navigatorKey), 106 | ), 107 | ], 108 | child: GetMaterialApp( 109 | title: "OCY Client", 110 | navigatorKey: navigatorKey, 111 | theme: ThemeData( 112 | appBarTheme: const AppBarTheme( 113 | color: Colors.white, 114 | centerTitle: false, 115 | elevation: 2, 116 | iconTheme: IconThemeData( 117 | color: Colors.black, 118 | ), 119 | titleTextStyle: TextStyle( 120 | fontSize: 15, 121 | fontWeight: FontWeight.bold, 122 | fontFamily: "PublicSans", 123 | ), 124 | ), 125 | iconTheme: const IconThemeData( 126 | color: Colors.black, 127 | ), 128 | buttonTheme: const ButtonThemeData( 129 | textTheme: ButtonTextTheme.accent, 130 | ), 131 | colorScheme: const ColorScheme.light( 132 | primary: Color(0xff0f254e), 133 | ), 134 | primaryColor: const Color(0xff0f254e), 135 | textButtonTheme: TextButtonThemeData( 136 | style: TextButton.styleFrom( 137 | textStyle: const TextStyle( 138 | fontWeight: FontWeight.bold, 139 | fontFamily: "PublicSans", 140 | fontSize: 16, 141 | ), 142 | ).copyWith( 143 | foregroundColor: MaterialStateProperty.resolveWith( 144 | (states) { 145 | if (states.contains(MaterialState.hovered)) { 146 | return const Color(0xff0f254e); 147 | } 148 | return Colors.black; 149 | }, 150 | ), 151 | ), 152 | ), 153 | ), 154 | themeMode: ThemeMode.light, 155 | initialRoute: "/home", 156 | debugShowCheckedModeBanner: false, 157 | translations: AppTranslations(), 158 | supportedLocales: const [ 159 | Locale('en', 'US'), //English 160 | Locale('bn', 'IN'), //Bengali 161 | ], 162 | locale: const Locale('en', 'US'), 163 | localizationsDelegates: const [ 164 | GlobalMaterialLocalizations.delegate, 165 | GlobalWidgetsLocalizations.delegate, 166 | GlobalCupertinoLocalizations.delegate, 167 | ], 168 | getPages: [ 169 | GetPage( 170 | name: '/home', 171 | page: () => const HomePage(), 172 | ), 173 | GetPage( 174 | name: '/', 175 | page: () => const HomePage(), 176 | ), 177 | GetPage( 178 | name: '/community', 179 | page: () => const CommunityPage(), 180 | ), 181 | GetPage( 182 | name: '/about_us', 183 | page: () => const AboutUsPage(), 184 | ), 185 | GetPage( 186 | name: '/milestones', 187 | page: () => const MilestonesPage(), 188 | ), 189 | GetPage( 190 | name: '/teams', 191 | page: () => const TeamsPage(), 192 | ), 193 | GetPage( 194 | name: '/auth', 195 | page: () => const LoginSignUp(), 196 | ), 197 | GetPage( 198 | name: '/profile', 199 | page: () => const ProfilePage(), 200 | ), 201 | GetPage( 202 | name: '/editProfile', 203 | page: () => const EditProfilePage(), 204 | ), 205 | GetPage( 206 | name: '/licenses', 207 | page: () => LicensePage( 208 | applicationIcon: Image.asset("assets/images/ocy_logo.png"), 209 | applicationName: "Open Codeyard", 210 | applicationVersion: Config.appVersion, 211 | ), 212 | ), 213 | ], 214 | ), 215 | ); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /lib/widgets/Teams/teams.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:ocyclient/blocs/teams_bloc.dart'; 4 | import 'package:ocyclient/models/team/team_model.dart'; 5 | import 'package:ocyclient/widgets/Teams/team_card.dart'; 6 | import 'package:ocyclient/widgets/Utils/ocy_scaffold.dart'; 7 | import 'package:provider/provider.dart'; 8 | 9 | class TeamsPage extends StatefulWidget { 10 | const TeamsPage({Key? key}) : super(key: key); 11 | 12 | @override 13 | State createState() => _TeamsPageState(); 14 | } 15 | 16 | class _TeamsPageState extends State { 17 | @override 18 | Widget build(BuildContext context) { 19 | SystemChrome.setApplicationSwitcherDescription( 20 | ApplicationSwitcherDescription( 21 | label: 'Teams 🏘️', 22 | primaryColor: Theme.of(context).primaryColor.value, 23 | ), 24 | ); 25 | 26 | Size size = MediaQuery.of(context).size; 27 | 28 | TeamsBloc tb = Provider.of(context); 29 | 30 | return OcyScaffold( 31 | body: SingleChildScrollView( 32 | physics: const BouncingScrollPhysics(), 33 | child: SizedBox( 34 | width: size.width, 35 | child: Column( 36 | crossAxisAlignment: CrossAxisAlignment.start, 37 | children: [ 38 | Container( 39 | height: size.width < 650 ? size.height / 1.6 : size.height, 40 | width: size.width, 41 | padding: EdgeInsets.only(left: size.width * 0.1), 42 | decoration: const BoxDecoration( 43 | image: DecorationImage( 44 | image: NetworkImage( 45 | "https://i.imgur.com/SHXoCoG.png", 46 | ), 47 | fit: BoxFit.cover, 48 | ), 49 | color: Color(0xff071a2b), 50 | ), 51 | child: Column( 52 | crossAxisAlignment: CrossAxisAlignment.start, 53 | children: [ 54 | const SizedBox( 55 | height: 150, 56 | ), 57 | SizedBox( 58 | width: size.width / (size.width > 550 ? 2 : 1), 59 | child: Text( 60 | "Teams are\nour pillars".toUpperCase(), 61 | style: TextStyle( 62 | fontFamily: "PublicSans", 63 | fontWeight: FontWeight.w700, 64 | fontSize: size.width > 1100 65 | ? 100 66 | : size.width > 800 67 | ? 60 68 | : 40, 69 | foreground: Paint() 70 | ..strokeWidth = 2 71 | ..style = PaintingStyle.stroke 72 | ..color = Colors.white, 73 | ), 74 | ), 75 | ), 76 | const SizedBox( 77 | height: 50, 78 | ), 79 | SizedBox( 80 | width: size.width / (size.width > 450 ? 2.4 : 1.2), 81 | child: Text( 82 | "If you believe in diversity, we believe you'll fit right in." 83 | " Be a part of something refreshing and revolutionary. " 84 | "Check out available roles below ", 85 | style: TextStyle( 86 | fontFamily: "PublicSans", 87 | color: Colors.white, 88 | fontWeight: FontWeight.bold, 89 | fontSize: size.width > 1100 90 | ? 25 91 | : size.width > 650 92 | ? 20 93 | : 18, 94 | ), 95 | ), 96 | ), 97 | ], 98 | ), 99 | ), 100 | Container( 101 | decoration: const BoxDecoration( 102 | color: Color(0xff071a2b), 103 | ), 104 | width: size.width, 105 | child: tb.isLoading 106 | ? SizedBox( 107 | height: 250, 108 | width: size.width, 109 | child: const Center( 110 | child: CircularProgressIndicator( 111 | color: Color(0xff8aafcc), 112 | ), 113 | ), 114 | ) 115 | : Padding( 116 | padding: const EdgeInsets.only(top: 25.0), 117 | child: Column( 118 | mainAxisAlignment: MainAxisAlignment.start, 119 | children: [ 120 | Padding( 121 | padding: EdgeInsets.symmetric( 122 | horizontal: size.width > 800 ? 100 : 15, 123 | ), 124 | child: size.width > 800 125 | ? Row( 126 | crossAxisAlignment: 127 | CrossAxisAlignment.center, 128 | children: [ 129 | Column( 130 | children: "TEAMS" 131 | .split("") 132 | .map((string) => Text( 133 | string, 134 | style: TextStyle( 135 | fontFamily: "PublicSans", 136 | fontWeight: 137 | FontWeight.bold, 138 | fontSize: 139 | size.width > 1100 140 | ? 140 141 | : 80, 142 | height: 1.5, 143 | foreground: Paint() 144 | ..strokeWidth = 1 145 | ..style = 146 | PaintingStyle.stroke 147 | ..color = const Color( 148 | 0xff8aafcc, 149 | ), 150 | ), 151 | )) 152 | .toList(), 153 | ), 154 | const SizedBox( 155 | width: 50, 156 | ), 157 | Expanded( 158 | child: getTeams(size, tb), 159 | ), 160 | ], 161 | ) 162 | : Column( 163 | children: [ 164 | Text( 165 | "TEAMS", 166 | style: TextStyle( 167 | fontFamily: "PublicSans", 168 | fontWeight: FontWeight.bold, 169 | fontSize: 60, 170 | letterSpacing: 5, 171 | foreground: Paint() 172 | ..strokeWidth = 1 173 | ..style = PaintingStyle.stroke 174 | ..color = const Color(0xff8aafcc), 175 | ), 176 | ), 177 | getTeams(size, tb), 178 | ], 179 | ), 180 | ) 181 | ], 182 | ), 183 | ), 184 | ) 185 | ], 186 | ), 187 | ), 188 | ), 189 | ); 190 | } 191 | 192 | Widget getTeams(Size size, TeamsBloc tb) { 193 | return ListView.builder( 194 | physics: const NeverScrollableScrollPhysics(), 195 | shrinkWrap: true, 196 | itemCount: tb.teams.length, 197 | itemBuilder: (context, index) { 198 | Team t = tb.teams[index]; 199 | return TeamCard( 200 | size: size, 201 | title: t.name, 202 | members: t.members, 203 | ); 204 | }, 205 | ); 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /lib/widgets/Utils/navigation_drawer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ocyclient/blocs/auth_bloc.dart'; 3 | import 'package:ocyclient/blocs/navigation_bloc.dart'; 4 | import 'package:ocyclient/configs/config.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | class AppDrawer extends StatefulWidget { 8 | const AppDrawer({Key? key}) : super(key: key); 9 | 10 | @override 11 | AppDrawerState createState() => AppDrawerState(); 12 | } 13 | 14 | class AppDrawerState extends State { 15 | String getRoute(String title) { 16 | switch (title) { 17 | case 'Events Calendar': 18 | return '/eventCalendar'; 19 | case 'Best Destinations': 20 | return '/destination'; 21 | case 'Special Offers': 22 | return '/specialOffer'; 23 | case 'Request Artist': 24 | return '/Artists'; 25 | case 'Contact Us': 26 | return '/contactus'; 27 | case 'News Alert': 28 | return '/newsLetter'; 29 | default: 30 | return '/home'; 31 | } 32 | } 33 | 34 | final List _amIHovering = [false, false, false, false, false, false]; 35 | 36 | @override 37 | Widget build(BuildContext context) { 38 | double width = MediaQuery.of(context).size.width / 1.5; 39 | 40 | double height = MediaQuery.of(context).size.height; 41 | String? name = ModalRoute.of(context)?.settings.name; 42 | 43 | NavigationBloc nb = Provider.of(context); 44 | AuthenticationBloc ab = Provider.of(context); 45 | 46 | return SizedBox( 47 | width: width, 48 | height: height, 49 | child: Drawer( 50 | backgroundColor: Colors.white, 51 | child: Column( 52 | children: [ 53 | Container( 54 | height: 161 + MediaQuery.of(context).padding.top, 55 | margin: EdgeInsets.zero, 56 | padding: const EdgeInsets.all(20), 57 | decoration: BoxDecoration( 58 | borderRadius: const BorderRadius.only( 59 | bottomLeft: Radius.circular(25), 60 | // bottomRight: Radius.circular(20), 61 | ), 62 | color: const Color(0xff071a2b), 63 | border: Border.all(color: Colors.transparent), 64 | ), 65 | child: Column( 66 | crossAxisAlignment: CrossAxisAlignment.start, 67 | mainAxisAlignment: MainAxisAlignment.end, 68 | children: [ 69 | Row( 70 | mainAxisAlignment: MainAxisAlignment.start, 71 | crossAxisAlignment: CrossAxisAlignment.center, 72 | children: [ 73 | GestureDetector( 74 | onTap: () { 75 | if (ab.isLoggedIn) { 76 | nb.toRoute("/profile"); 77 | } else { 78 | nb.toRoute("/auth"); 79 | } 80 | }, 81 | child: Container( 82 | height: 60, 83 | width: 60, 84 | decoration: BoxDecoration( 85 | borderRadius: BorderRadius.circular(10), 86 | color: Colors.white, 87 | border: Border.all( 88 | color: Colors.blueGrey, 89 | width: 3, 90 | ), 91 | ), 92 | child: ab.isLoggedIn 93 | ? ClipRRect( 94 | borderRadius: BorderRadius.circular(4), 95 | child: 96 | Image.network(ab.userModel.profilePicUrl), 97 | ) 98 | : const Icon( 99 | Icons.person, 100 | color: Colors.black, 101 | ), 102 | ), 103 | ), 104 | const SizedBox( 105 | width: 15, 106 | ), 107 | ], 108 | ), 109 | const SizedBox( 110 | height: 15, 111 | ), 112 | Padding( 113 | padding: 114 | const EdgeInsets.symmetric(horizontal: 4, vertical: 4), 115 | child: Text( 116 | "Hello 👋, ${ab.isLoggedIn ? getFirstName(ab.userModel.name) : "Guest"}", 117 | style: const TextStyle( 118 | color: Colors.white, 119 | fontSize: 20, 120 | ), 121 | ), 122 | ), 123 | ], 124 | ), 125 | ), 126 | const SizedBox( 127 | height: 20, 128 | ), 129 | Expanded( 130 | child: ListView( 131 | padding: const EdgeInsets.all(5), 132 | scrollDirection: Axis.vertical, 133 | physics: const BouncingScrollPhysics(), 134 | shrinkWrap: true, 135 | children: [ 136 | ...List.generate( 137 | Config.routeNames.length, 138 | (index) { 139 | bool selected = isSelected(name, index); 140 | return drawerItem( 141 | index, 142 | selected, 143 | null, 144 | ); 145 | }, 146 | ), 147 | if (ab.isLoggedIn) 148 | drawerItem( 149 | 5, 150 | false, 151 | () { 152 | ab.signOut(context, nb); 153 | }, 154 | ), 155 | ], 156 | ), 157 | ), 158 | Text( 159 | "v${Config.appVersion}", 160 | style: TextStyle( 161 | color: Theme.of(context).primaryColor, 162 | fontWeight: FontWeight.bold, 163 | fontSize: 19, 164 | fontFamily: "PublicSans", 165 | ), 166 | ), 167 | const SizedBox( 168 | height: 15, 169 | ), 170 | ], 171 | ), 172 | ), 173 | ); 174 | } 175 | 176 | String getFirstName(String name) { 177 | if (name.split(" ").length > 1) { 178 | return name.split(" ")[0]; 179 | } else { 180 | return name.substring(0, 8); 181 | } 182 | } 183 | 184 | bool isSelected(String? name, int index) { 185 | return name != null && name == Config.routeNames.values.toList()[index]; 186 | } 187 | 188 | Widget drawerItem(int index, bool selected, void Function()? onTap) { 189 | return GestureDetector( 190 | onTap: () { 191 | if (onTap == null) { 192 | Navigator.of(context).pushNamed( 193 | Config.routeNames.values.toList()[index], 194 | ); 195 | } else { 196 | onTap(); 197 | } 198 | }, 199 | child: MouseRegion( 200 | onEnter: (details) { 201 | setState(() { 202 | _amIHovering[index] = true; 203 | }); 204 | }, 205 | onExit: (details) => setState(() { 206 | _amIHovering[index] = false; 207 | }), 208 | cursor: SystemMouseCursors.click, 209 | child: Card( 210 | shape: RoundedRectangleBorder( 211 | borderRadius: BorderRadius.circular( 212 | 8, 213 | ), 214 | ), 215 | elevation: selected || _amIHovering[index] ? 5 : 0, 216 | child: ClipPath( 217 | clipper: ShapeBorderClipper( 218 | shape: RoundedRectangleBorder( 219 | borderRadius: BorderRadius.circular( 220 | 8, 221 | ), 222 | ), 223 | ), 224 | child: Container( 225 | decoration: BoxDecoration( 226 | border: selected 227 | ? const Border( 228 | left: BorderSide( 229 | color: Color(0xff071a2b), 230 | width: 5, 231 | ), 232 | ) 233 | : _amIHovering[index] 234 | ? Border( 235 | left: BorderSide( 236 | color: index == 5 ? Colors.red : Colors.indigo, 237 | width: 5, 238 | ), 239 | ) 240 | : null, 241 | ), 242 | padding: const EdgeInsets.symmetric(vertical: 15.0), 243 | child: Row( 244 | children: [ 245 | const SizedBox( 246 | width: 10, 247 | ), 248 | Icon( 249 | selected || _amIHovering[index] 250 | ? Config.selectedAppDrawerIcons[index] 251 | : Config.appDrawerIcons[index], 252 | size: selected || _amIHovering[index] ? 18 : 25, 253 | ), 254 | const SizedBox( 255 | width: 20, 256 | ), 257 | Text( 258 | index == 5 259 | ? "Log Out" 260 | : Config.routeNames.keys.toList()[index], 261 | style: TextStyle( 262 | fontSize: 19, 263 | fontFamily: "PublicSans", 264 | fontWeight: selected || _amIHovering[index] 265 | ? FontWeight.w700 266 | : FontWeight.normal, 267 | color: selected ? const Color(0xff071a2b) : Colors.black, 268 | ), 269 | ), 270 | ], 271 | ), 272 | ), 273 | ), 274 | ), 275 | ), 276 | ); 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /lib/widgets/Auth/login_signup.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ocyclient/blocs/auth_bloc.dart'; 3 | import 'package:ocyclient/blocs/navigation_bloc.dart'; 4 | import 'package:ocyclient/widgets/Auth/page_view/login_intro_page.dart'; 5 | import 'package:ocyclient/widgets/Utils/ocy_scaffold.dart'; 6 | import 'package:ocyclient/widgets/Utils/snackbar.dart'; 7 | import 'package:provider/provider.dart'; 8 | import 'package:step_progress_indicator/step_progress_indicator.dart'; 9 | 10 | class LoginSignUp extends StatefulWidget { 11 | const LoginSignUp({Key? key}) : super(key: key); 12 | 13 | @override 14 | LoginSignUpState createState() => LoginSignUpState(); 15 | } 16 | 17 | class LoginSignUpState extends State { 18 | final PageController _pageController = PageController(keepPage: true); 19 | int _currentPage = 0; 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | Size size = MediaQuery.of(context).size; 24 | AuthenticationBloc ab = Provider.of(context); 25 | NavigationBloc nb = Provider.of(context); 26 | 27 | return OcyScaffold( 28 | enableSelection: false, 29 | body: Center( 30 | child: SizedBox( 31 | height: size.width < 600 ? size.height : size.height * 0.8, 32 | width: size.width < 600 ? size.width : size.width * 0.9, 33 | child: Card( 34 | elevation: 15, 35 | shape: size.width < 600 36 | ? null 37 | : RoundedRectangleBorder( 38 | borderRadius: BorderRadius.circular(15), 39 | ), 40 | child: size.width < 600 41 | ? loginWidget(size, ab, nb, true) 42 | : size.width < 1000 43 | ? introWidgets(size, true, ab: ab, nb: nb) 44 | : Row( 45 | children: [ 46 | introWidgets(size, false), 47 | loginWidget(size, ab, nb, false), 48 | ], 49 | ), 50 | ), 51 | ), 52 | ), 53 | ); 54 | } 55 | 56 | introWidgets(Size size, bool isMobile, 57 | {AuthenticationBloc? ab, NavigationBloc? nb}) { 58 | return SizedBox( 59 | width: isMobile 60 | ? size.width < 600 61 | ? size.width 62 | : size.width * 0.9 63 | : size.width * 0.45, 64 | height: size.width < 600 ? size.height : size.height * 0.8, 65 | child: Stack( 66 | children: [ 67 | PageView( 68 | scrollDirection: Axis.vertical, 69 | controller: _pageController, 70 | onPageChanged: (int page) { 71 | setState(() { 72 | _currentPage = page; 73 | }); 74 | }, 75 | children: [ 76 | const LoginIntroPage( 77 | title: "Welcome", 78 | subtitle: 'to the gateway of infinite possibilities', 79 | imagePath: "assets/images/welcome.jpg", 80 | ), 81 | const LoginIntroPage( 82 | title: "Events", 83 | subtitle: 'Gain access to exclusive events and tech fests', 84 | imagePath: "assets/images/events.jpg", 85 | ), 86 | //https://unsplash.com/@jannerboy62 87 | const LoginIntroPage( 88 | title: "Projects", 89 | subtitle: 90 | 'Manage all your teams and contributions in one place', 91 | imagePath: "assets/images/teams.jpg", 92 | ), 93 | if (isMobile) loginWidget(size, ab!, nb!, true), 94 | ], 95 | ), 96 | Positioned( 97 | top: 15, 98 | right: 30, 99 | child: StepProgressIndicator( 100 | totalSteps: isMobile ? 4 : 3, 101 | currentStep: _currentPage + 1, 102 | size: 4, 103 | padding: 0.5, 104 | selectedColor: Colors.amberAccent, 105 | unselectedColor: Colors.white, 106 | roundedEdges: const Radius.circular(10), 107 | onTap: (int index) { 108 | return () { 109 | _pageController.animateToPage( 110 | index, 111 | duration: const Duration(seconds: 1), 112 | curve: Curves.fastOutSlowIn, 113 | ); 114 | }; 115 | }, 116 | direction: Axis.vertical, 117 | ), 118 | ), 119 | ], 120 | ), 121 | ); 122 | } 123 | 124 | loginWidget( 125 | Size size, AuthenticationBloc ab, NavigationBloc nb, bool isMobile) { 126 | return SizedBox( 127 | width: isMobile 128 | ? size.width < 600 129 | ? size.width 130 | : size.width * 0.9 131 | : size.width * 0.45 - 8, 132 | child: Column( 133 | crossAxisAlignment: CrossAxisAlignment.center, 134 | mainAxisAlignment: MainAxisAlignment.center, 135 | children: [ 136 | Image.asset( 137 | "assets/images/ocy_logo.png", 138 | height: 150, 139 | width: 150, 140 | ), 141 | RichText( 142 | text: TextSpan( 143 | text: "{", 144 | style: TextStyle( 145 | fontSize: size.width < 1100 && size.width > 900 ? 22 : 28, 146 | fontWeight: FontWeight.bold, 147 | color: Colors.black, 148 | ), 149 | children: [ 150 | TextSpan( 151 | text: " Open ", 152 | style: TextStyle( 153 | fontSize: size.width < 1100 && size.width > 900 ? 22 : 28, 154 | fontWeight: FontWeight.normal, 155 | color: Colors.grey.shade700, 156 | fontFamily: "PublicSans", 157 | ), 158 | ), 159 | TextSpan( 160 | text: "Codeyard ", 161 | style: TextStyle( 162 | fontSize: size.width < 1100 && size.width > 900 ? 22 : 28, 163 | fontWeight: FontWeight.bold, 164 | fontFamily: "PublicSans", 165 | color: Colors.black, 166 | ), 167 | ), 168 | TextSpan( 169 | text: "} ;", 170 | style: TextStyle( 171 | fontSize: size.width < 1100 && size.width > 900 ? 22 : 28, 172 | fontWeight: FontWeight.bold, 173 | color: Colors.black, 174 | ), 175 | ), 176 | ], 177 | ), 178 | ), 179 | const SizedBox( 180 | height: 35, 181 | ), 182 | const Text( 183 | "Your journey to open source development starts here", 184 | textAlign: TextAlign.center, 185 | style: TextStyle( 186 | fontFamily: "PublicSans", 187 | fontSize: 18, 188 | ), 189 | ), 190 | const SizedBox( 191 | height: 35, 192 | ), 193 | SizedBox( 194 | height: 50, 195 | child: ElevatedButton.icon( 196 | style: ElevatedButton.styleFrom( 197 | backgroundColor: Colors.white, 198 | shape: RoundedRectangleBorder( 199 | borderRadius: BorderRadius.circular(15), 200 | ), 201 | padding: const EdgeInsets.all(15), 202 | ).copyWith( 203 | elevation: MaterialStateProperty.resolveWith( 204 | (Set states) { 205 | // if the button is pressed the elevation is 10.0, if not 206 | // it is 5.0 207 | if (states.contains(MaterialState.pressed)) { 208 | return 5.0; 209 | } 210 | return 10.0; 211 | }, 212 | ), 213 | ), 214 | onPressed: () { 215 | if (ab.inProgress) { 216 | showToast("Please wait. Login in progress"); 217 | return; 218 | } 219 | ab.authWithGoogle(nb, false); 220 | }, 221 | icon: !isMobile && ab.isGoogleSignInOngoing 222 | ? Stack( 223 | alignment: Alignment.center, 224 | children: [ 225 | Image.asset( 226 | "assets/images/google_logo.png", 227 | width: 30, 228 | height: 30, 229 | ), 230 | const Center( 231 | child: CircularProgressIndicator( 232 | color: Color(0xff87ceeb), 233 | ), 234 | ), 235 | ], 236 | ) 237 | : Image.asset( 238 | "assets/images/google_logo.png", 239 | width: 30, 240 | height: 30, 241 | ), 242 | label: const Text( 243 | "Continue with Google", 244 | style: TextStyle( 245 | color: Colors.black, 246 | fontWeight: FontWeight.bold, 247 | fontSize: 16, 248 | ), 249 | ), 250 | ), 251 | ), 252 | const SizedBox( 253 | height: 30, 254 | ), 255 | SizedBox( 256 | height: 50, 257 | child: ElevatedButton.icon( 258 | style: ElevatedButton.styleFrom( 259 | backgroundColor: Colors.white, 260 | shape: RoundedRectangleBorder( 261 | borderRadius: BorderRadius.circular(15), 262 | ), 263 | padding: const EdgeInsets.all(15), 264 | ).copyWith( 265 | elevation: MaterialStateProperty.resolveWith( 266 | (Set states) { 267 | // if the button is pressed the elevation is 10.0, if not 268 | // it is 5.0 269 | if (states.contains(MaterialState.pressed)) { 270 | return 5.0; 271 | } 272 | return 10.0; 273 | }, 274 | ), 275 | ), 276 | onPressed: () { 277 | if (ab.inProgress) { 278 | showToast("Please wait. Login in progress"); 279 | return; 280 | } 281 | ab.authWithGithub(context, nb, false); 282 | }, 283 | icon: !isMobile && ab.isGithubSignInOngoing 284 | ? Stack( 285 | alignment: Alignment.center, 286 | children: [ 287 | Image.asset( 288 | "assets/images/github_logo.png", 289 | width: 30, 290 | height: 30, 291 | ), 292 | const Center( 293 | child: CircularProgressIndicator( 294 | color: Color(0xff87ceeb), 295 | ), 296 | ), 297 | ], 298 | ) 299 | : Image.asset( 300 | "assets/images/github_logo.png", 301 | width: 30, 302 | height: 30, 303 | ), 304 | label: const Text( 305 | "Continue with Github", 306 | style: TextStyle( 307 | color: Colors.black, 308 | fontWeight: FontWeight.bold, 309 | fontSize: 16, 310 | ), 311 | ), 312 | ), 313 | ), 314 | ], 315 | ), 316 | ); 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /lib/widgets/Home/sub_pages/benefits.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:line_icons/line_icons.dart'; 3 | import 'package:ocyclient/configs/config.dart'; 4 | import 'package:ocyclient/widgets/Utils/measure_size_render_object.dart'; 5 | import 'package:ocyclient/widgets/Utils/snackbar.dart'; 6 | import 'package:url_launcher/url_launcher_string.dart'; 7 | 8 | class Benefits extends StatefulWidget { 9 | const Benefits({Key? key}) : super(key: key); 10 | 11 | @override 12 | BenefitsState createState() => BenefitsState(); 13 | } 14 | 15 | class BenefitsState extends State { 16 | final List _amIHovering = [false, false, false]; 17 | 18 | double cardHeight = 0; 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | Size size = MediaQuery.of(context).size; 23 | 24 | return SizedBox( 25 | width: size.width, 26 | height: size.width > 950 27 | ? size.height * 0.8 - 50 28 | : size.width > 800 29 | ? size.height * 0.8 - 20 30 | : size.height * 0.9 - 100, 31 | child: Column( 32 | children: [ 33 | const SizedBox( 34 | height: 25, 35 | ), 36 | Text( 37 | "Why Open Source ?", 38 | style: TextStyle( 39 | fontSize: size.width > 800 40 | ? 40 41 | : size.width > 400 42 | ? 35 43 | : 25, 44 | fontWeight: FontWeight.w700, 45 | fontFamily: "PublicSans", 46 | color: const Color(0xff071a2b), 47 | ), 48 | ), 49 | const SizedBox( 50 | height: 40, 51 | ), 52 | SizedBox( 53 | width: size.width > 400 ? size.width / 1.5 : size.width, 54 | child: Text( 55 | "We believe software should be free for all." 56 | "\nUnder our open source program we plan to reduce the economic gaps of society.", 57 | textAlign: TextAlign.center, 58 | style: TextStyle( 59 | fontSize: size.width > 800 ? 16 : 14, 60 | fontFamily: "PublicSans", 61 | color: Colors.black, 62 | ), 63 | ), 64 | ), 65 | const SizedBox( 66 | height: 40, 67 | ), 68 | Flexible( 69 | child: Center( 70 | child: ListView( 71 | shrinkWrap: true, 72 | padding: const EdgeInsets.all(20), 73 | physics: const BouncingScrollPhysics(), 74 | scrollDirection: Axis.horizontal, 75 | children: [ 76 | getBenefitsCard( 77 | size, 78 | "Learn", 79 | "Be a part of great projects that enhance your career and skills.", 80 | 0, 81 | const Color(0xff071a2b), 82 | LineIcons.graduationCap, 83 | Row( 84 | mainAxisAlignment: MainAxisAlignment.center, 85 | children: [ 86 | IconButton( 87 | icon: Icon( 88 | LineIcons.github, 89 | color: _amIHovering[0] 90 | ? const Color(0xffe8f9ff) 91 | : Colors.black, 92 | ), 93 | iconSize: 35, 94 | tooltip: "GitHub", 95 | onPressed: () { 96 | launchUrlString("https://github.com/OpenCodeyard"); 97 | }, 98 | ), 99 | ], 100 | ), 101 | ), 102 | const SizedBox( 103 | width: 40, 104 | ), 105 | getBenefitsCard( 106 | size, 107 | "Community", 108 | "Projects powered by a community that will " 109 | "always have a people first approach.", 110 | 1, 111 | const Color(0xff1e2e68), 112 | LineIcons.peopleCarry, 113 | Row( 114 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 115 | children: [ 116 | IconButton( 117 | icon: Icon( 118 | LineIcons.linkedinIn, 119 | color: _amIHovering[1] 120 | ? const Color(0xffe8f9ff) 121 | : Colors.black, 122 | ), 123 | iconSize: 35, 124 | tooltip: "LinkedIn", 125 | onPressed: () { 126 | launchUrlString(Config.linkedInUrl); 127 | }, 128 | ), 129 | IconButton( 130 | icon: Icon( 131 | LineIcons.discord, 132 | color: _amIHovering[1] 133 | ? const Color(0xffe8f9ff) 134 | : Colors.black, 135 | ), 136 | tooltip: "Discord", 137 | iconSize: 35, 138 | onPressed: () { 139 | showToast("Coming Soon"); 140 | }, 141 | ), 142 | IconButton( 143 | icon: Icon( 144 | LineIcons.telegram, 145 | color: _amIHovering[1] 146 | ? const Color(0xffe8f9ff) 147 | : Colors.black, 148 | ), 149 | tooltip: "Telegram", 150 | iconSize: 35, 151 | onPressed: () { 152 | launchUrlString(Config.telegramUrl); 153 | }, 154 | ), 155 | ], 156 | ), 157 | ), 158 | const SizedBox( 159 | width: 40, 160 | ), 161 | getBenefitsCard( 162 | size, 163 | "Events", 164 | "Join live events that are great fun.", 165 | 2, 166 | const Color(0xff242435), 167 | LineIcons.calendarWithWeekFocus, 168 | null, 169 | ), 170 | ], 171 | ), 172 | ), 173 | ), 174 | ], 175 | ), 176 | ); 177 | } 178 | 179 | Widget getBenefitsCard( 180 | Size size, 181 | String title, 182 | String subtitle, 183 | int index, 184 | Color iconColor, 185 | IconData icon, 186 | Widget? extra, 187 | ) { 188 | return MeasureSize( 189 | onChange: (Size size) { 190 | cardHeight = size.height; 191 | }, 192 | key: Key(index.toString()), 193 | child: MouseRegion( 194 | onEnter: (details) { 195 | setState(() { 196 | _amIHovering[index] = true; 197 | }); 198 | }, 199 | onExit: (details) => setState(() { 200 | _amIHovering[index] = false; 201 | }), 202 | child: SizedBox( 203 | width: size.width / 5 < 300 ? 300 : size.width / 5, 204 | child: Card( 205 | elevation: _amIHovering[index] ? 35 : 5, 206 | shape: RoundedRectangleBorder( 207 | borderRadius: BorderRadius.circular(20), 208 | ), 209 | child: Stack( 210 | children: [ 211 | Positioned( 212 | left: 0, 213 | bottom: 0, 214 | child: AnimatedContainer( 215 | width: _amIHovering[index] 216 | ? size.width / 5 < 300 217 | ? 300 - 8 218 | : size.width / 5 - 8 219 | : 0, 220 | height: _amIHovering[index] ? cardHeight - 8 : 0, 221 | decoration: BoxDecoration( 222 | borderRadius: BorderRadius.circular(20), 223 | color: iconColor, 224 | ), 225 | duration: const Duration( 226 | milliseconds: 1000, 227 | ), 228 | curve: Curves.easeOutQuint, 229 | ), 230 | ), 231 | Padding( 232 | padding: 233 | const EdgeInsets.only(left: 25.0, right: 25.0, top: 25.0), 234 | child: Column( 235 | crossAxisAlignment: CrossAxisAlignment.center, 236 | children: [ 237 | Icon( 238 | icon, 239 | size: 60, 240 | color: _amIHovering[index] 241 | ? const Color(0xffe8f9ff) 242 | : Colors.black, 243 | ), 244 | const SizedBox( 245 | height: 15, 246 | ), 247 | Text( 248 | title, 249 | style: TextStyle( 250 | fontSize: 25, 251 | fontFamily: "PublicSans", 252 | color: _amIHovering[index] 253 | ? const Color(0xffe8f9ff) 254 | : Colors.black, 255 | fontWeight: FontWeight.w700, 256 | ), 257 | ), 258 | const SizedBox( 259 | height: 25, 260 | ), 261 | Text( 262 | subtitle, 263 | textAlign: TextAlign.center, 264 | style: TextStyle( 265 | fontSize: 16, 266 | height: 1.5, 267 | color: _amIHovering[index] 268 | ? const Color(0xffe8f9ff) 269 | : Colors.black, 270 | fontFamily: "PublicSans", 271 | ), 272 | ), 273 | const SizedBox( 274 | height: 25, 275 | ), 276 | extra ?? const SizedBox(), 277 | ], 278 | ), 279 | ), 280 | Positioned( 281 | right: -(size.width / 5 < 300 ? 300 : size.width / 5) / 10, 282 | bottom: -(size.width / 5 < 300 ? 300 : size.width / 5) / 10, 283 | child: AnimatedContainer( 284 | width: _amIHovering[index] 285 | ? (size.width / 5 < 300 ? 300 : size.width / 5) / 4 286 | : 0, 287 | height: _amIHovering[index] 288 | ? (size.width / 5 < 300 ? 300 : size.width / 5) / 4 289 | : 0, 290 | decoration: BoxDecoration( 291 | borderRadius: BorderRadius.circular(40), 292 | border: Border.all( 293 | color: const Color(0xffe8f9ff), 294 | width: 4, 295 | ), 296 | color: Colors.transparent, 297 | ), 298 | duration: const Duration( 299 | milliseconds: 1400, 300 | ), 301 | curve: Curves.easeOutQuint, 302 | ), 303 | ), 304 | Positioned( 305 | left: -(size.width / 5 < 300 ? 300 : size.width / 5) / 10, 306 | top: -(size.width / 5 < 300 ? 300 : size.width / 5) / 10, 307 | child: AnimatedContainer( 308 | width: _amIHovering[index] 309 | ? (size.width / 5 < 300 ? 300 : size.width / 5) / 4 310 | : 0, 311 | height: _amIHovering[index] 312 | ? (size.width / 5 < 300 ? 300 : size.width / 5) / 4 313 | : 0, 314 | decoration: BoxDecoration( 315 | borderRadius: BorderRadius.circular(40), 316 | border: Border.all( 317 | color: const Color(0xffe8f9ff), 318 | width: 4, 319 | ), 320 | color: Colors.transparent, 321 | ), 322 | duration: const Duration( 323 | milliseconds: 1400, 324 | ), 325 | curve: Curves.easeOutQuint, 326 | ), 327 | ), 328 | ], 329 | ), 330 | ), 331 | ), 332 | ), 333 | ); 334 | } 335 | } 336 | -------------------------------------------------------------------------------- /lib/widgets/Profile/profile.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 3 | import 'package:ocyclient/blocs/auth_bloc.dart'; 4 | import 'package:ocyclient/blocs/navigation_bloc.dart'; 5 | import 'package:ocyclient/blocs/profile_bloc.dart'; 6 | import 'package:ocyclient/widgets/Profile/sub_pages/profile_user.dart'; 7 | import 'package:ocyclient/widgets/Utils/common_widgets.dart'; 8 | import 'package:ocyclient/widgets/Utils/ocy_scaffold.dart'; 9 | import 'package:provider/provider.dart'; 10 | 11 | class ProfilePage extends StatefulWidget { 12 | const ProfilePage({Key? key}) : super(key: key); 13 | 14 | @override 15 | ProfilePageState createState() => ProfilePageState(); 16 | } 17 | 18 | class ProfilePageState extends State { 19 | ///TODO cover attribution Background vector created by freepik - www.freepik.com 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | Size size = MediaQuery.of(context).size; 24 | 25 | ProfileBloc pb = Provider.of(context); 26 | AuthenticationBloc ab = Provider.of(context); 27 | NavigationBloc nb = Provider.of(context); 28 | 29 | return OcyScaffold( 30 | body: SizedBox( 31 | height: size.height - 70, 32 | child: size.width < 1000 33 | ? SingleChildScrollView( 34 | physics: const BouncingScrollPhysics(), 35 | child: Column( 36 | children: [ 37 | const SizedBox( 38 | height: 20, 39 | ), 40 | Padding( 41 | padding: const EdgeInsets.symmetric(horizontal: 8.0), 42 | child: Card( 43 | elevation: 10, 44 | shape: RoundedRectangleBorder( 45 | borderRadius: BorderRadius.circular(15), 46 | ), 47 | child: SingleChildScrollView( 48 | scrollDirection: Axis.horizontal, 49 | padding: const EdgeInsets.symmetric( 50 | horizontal: 5, 51 | vertical: 10, 52 | ), 53 | child: Row( 54 | mainAxisAlignment: MainAxisAlignment.center, 55 | children: getProfileMenu(size, pb, ab, nb), 56 | ), 57 | ), 58 | ), 59 | ), 60 | const UserTab(), 61 | ], 62 | ), 63 | ) 64 | : Row( 65 | children: [ 66 | Card( 67 | elevation: 10, 68 | margin: EdgeInsets.zero, 69 | child: SizedBox( 70 | height: size.height, 71 | width: 230, 72 | child: SingleChildScrollView( 73 | physics: const BouncingScrollPhysics(), 74 | padding: const EdgeInsets.symmetric( 75 | horizontal: 25, 76 | vertical: 10, 77 | ), 78 | child: Column( 79 | children: getProfileMenu(size, pb, ab, nb), 80 | ), 81 | ), 82 | ), 83 | ), 84 | getVerticalDivider(), 85 | const UserTab(), 86 | // getVerticalDivider(), 87 | // Column( 88 | // children: [ 89 | // 90 | // Column( 91 | // crossAxisAlignment: CrossAxisAlignment.start, 92 | // children: [ 93 | // Container( 94 | // margin: const EdgeInsets.all(10), 95 | // child: const Text( 96 | // "Details", 97 | // style: TextStyle( 98 | // fontWeight: FontWeight.bold, 99 | // fontSize: 40, 100 | // fontFamily: "PublicSans", 101 | // ), 102 | // ), 103 | // ), 104 | // Container( 105 | // width: 295, 106 | // margin: const EdgeInsets.all(10), 107 | // child: Card( 108 | // elevation: 10, 109 | // shape: RoundedRectangleBorder( 110 | // borderRadius: BorderRadius.circular(20), 111 | // ), 112 | // child: Container( 113 | // padding: const EdgeInsets.all(20), 114 | // child: Column( 115 | // crossAxisAlignment: 116 | // CrossAxisAlignment.center, 117 | // children: [ 118 | // getIconifiedDetail( 119 | // ab.userModel.email.isEmpty 120 | // ? "Not Provided" 121 | // : ab.userModel.email, 122 | // FontAwesomeIcons.envelope, 123 | // Colors.red, 124 | // 200, 125 | // ), 126 | // const SizedBox( 127 | // height: 15, 128 | // ), 129 | // getIconifiedDetail( 130 | // "Government College of Engineering and Leather Technology", 131 | // FontAwesomeIcons.buildingColumns, 132 | // Colors.blue, 133 | // 200), 134 | // ], 135 | // ), 136 | // ), 137 | // ), 138 | // ), 139 | // ], 140 | // ), 141 | // Column( 142 | // crossAxisAlignment: CrossAxisAlignment.start, 143 | // children: [ 144 | // Container( 145 | // margin: const EdgeInsets.all(10), 146 | // child: const Text( 147 | // "Details", 148 | // style: TextStyle( 149 | // fontWeight: FontWeight.bold, 150 | // fontSize: 40, 151 | // fontFamily: "PublicSans", 152 | // ), 153 | // ), 154 | // ), 155 | // Container( 156 | // width: 260, 157 | // margin: const EdgeInsets.all(10), 158 | // child: Card( 159 | // elevation: 10, 160 | // shape: RoundedRectangleBorder( 161 | // borderRadius: BorderRadius.circular(20), 162 | // ), 163 | // child: Container( 164 | // padding: const EdgeInsets.all(20), 165 | // child: Column( 166 | // crossAxisAlignment: 167 | // CrossAxisAlignment.center, 168 | // children: [ 169 | // getIconifiedDetail( 170 | // (ab.userModel.locality?.isEmpty ?? true) 171 | // ? "Not Provided" 172 | // : ab.userModel.locality ?? "", 173 | // FontAwesomeIcons.locationDot, 174 | // Colors.red, 175 | // 170, 176 | // ), 177 | // const SizedBox( 178 | // height: 15, 179 | // ), 180 | // getIconifiedDetail( 181 | // (ab.userModel.dob?.isEmpty ?? true) 182 | // ? "Not Provided" 183 | // : ab.userModel.dob ?? "", 184 | // FontAwesomeIcons.calendarDays, 185 | // Colors.blue, 186 | // 170), 187 | // ], 188 | // ), 189 | // ), 190 | // ), 191 | // ), 192 | // ], 193 | // ), 194 | // ], 195 | // ) 196 | ], 197 | ), 198 | ), 199 | ); 200 | } 201 | 202 | Widget getVerticalDivider() { 203 | return const VerticalDivider( 204 | width: 1, 205 | color: Colors.black12, 206 | ); 207 | } 208 | 209 | List getProfileMenu( 210 | Size size, 211 | ProfileBloc pb, 212 | AuthenticationBloc ab, 213 | NavigationBloc nb, 214 | ) { 215 | bool isHorizontal = false; 216 | if (size.width < 1000) { 217 | isHorizontal = true; 218 | } 219 | return [ 220 | getCustomSizedBoxForMenu(isHorizontal), 221 | if (!isHorizontal) ...[ 222 | Image.asset( 223 | "assets/images/ocy_logo.png", 224 | width: 100, 225 | height: 100, 226 | ), 227 | const SizedBox( 228 | height: 30, 229 | ), 230 | ], 231 | getSideMenuButton( 232 | pb, 233 | "User", 234 | FontAwesomeIcons.userLarge, 235 | 0, 236 | isHorizontal, 237 | ), 238 | getCustomSizedBoxForMenu(isHorizontal), 239 | getSideMenuButton( 240 | pb, 241 | "My Events", 242 | FontAwesomeIcons.solidCalendarCheck, 243 | 1, 244 | isHorizontal, 245 | ), 246 | getCustomSizedBoxForMenu(isHorizontal), 247 | getSideMenuButton( 248 | pb, 249 | "My Projects", 250 | FontAwesomeIcons.codeBranch, 251 | 2, 252 | isHorizontal, 253 | ), 254 | getCustomSizedBoxForMenu(isHorizontal), 255 | getSideMenuButton( 256 | pb, 257 | "Log Out", 258 | FontAwesomeIcons.rightFromBracket, 259 | 3, 260 | isHorizontal, 261 | authBloc: ab, 262 | navBloc: nb, 263 | ), 264 | getCustomSizedBoxForMenu(isHorizontal), 265 | ]; 266 | } 267 | 268 | Widget getSideMenuButton( 269 | ProfileBloc pb, 270 | String title, 271 | IconData icon, 272 | int index, 273 | bool isHorizontal, { 274 | AuthenticationBloc? authBloc, 275 | NavigationBloc? navBloc, 276 | }) { 277 | return MouseRegion( 278 | cursor: SystemMouseCursors.click, 279 | child: GestureDetector( 280 | onTap: () { 281 | if (index == 3) { 282 | authBloc?.signOut(context, navBloc!); 283 | } else { 284 | pb.setCurrentSelectedItem(index); 285 | } 286 | }, 287 | child: AnimatedContainer( 288 | padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15), 289 | decoration: BoxDecoration( 290 | color: pb.currentSelectedMenuItem == index 291 | ? const Color(0x73c6dbec) 292 | : Colors.white, 293 | borderRadius: BorderRadius.circular(10), 294 | ), 295 | duration: const Duration(milliseconds: 500), 296 | curve: Curves.fastOutSlowIn, 297 | child: SizedBox( 298 | child: Row( 299 | children: [ 300 | Text( 301 | title, 302 | style: TextStyle( 303 | color: pb.currentSelectedMenuItem == index 304 | ? Colors.black 305 | : Colors.grey, 306 | fontWeight: pb.currentSelectedMenuItem == index 307 | ? FontWeight.bold 308 | : FontWeight.normal, 309 | fontSize: 14, 310 | fontFamily: "PublicSans"), 311 | ), 312 | if (isHorizontal) 313 | const SizedBox( 314 | width: 20, 315 | ) 316 | else 317 | const Spacer(), 318 | getIconForButton(icon), 319 | if (isHorizontal) 320 | const SizedBox( 321 | width: 10, 322 | ) 323 | ], 324 | ), 325 | ), 326 | ), 327 | ), 328 | ); 329 | } 330 | 331 | Widget getCustomSizedBoxForMenu(bool isHorizontal) { 332 | return isHorizontal 333 | ? const SizedBox( 334 | width: 30, 335 | ) 336 | : const SizedBox( 337 | height: 30, 338 | ); 339 | } 340 | } 341 | --------------------------------------------------------------------------------