├── ios ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist └── .gitignore ├── lib ├── respositories │ ├── respositories.dart │ ├── baseloadusersrepo.dart │ ├── base_storage_repository.dart │ ├── base_database_repository.dart │ ├── auth_repositoties.dart │ ├── bloc │ │ ├── auth_event.dart │ │ ├── image_event.dart │ │ ├── image_state.dart │ │ ├── serachstate.dart │ │ ├── auth_state.dart │ │ ├── swipebloc_state.dart │ │ ├── swipebloc_event.dart │ │ ├── search_event.dart │ │ ├── auth_bloc.dart │ │ ├── image_bloc.dart │ │ ├── swipebloc_bloc.dart │ │ └── searchbloc.dart │ ├── baseusers.dart │ ├── databerepository.dart │ ├── storage_repository.dart │ ├── mainauth.dart │ ├── usersrepo.dart │ └── searchrepository.dart ├── widgets │ ├── extensions.dart │ ├── header.dart │ ├── check_box.dart │ ├── custom_textfield.dart │ ├── small_image.dart │ ├── choicebtn.dart │ ├── custombtn.dart │ ├── custom_text_container.dart │ ├── image_container.dart │ └── likes.dart ├── constatns │ ├── colors.dart │ └── app_router.dart ├── pages │ ├── tabs │ │ ├── profile.dart │ │ ├── matching.dart │ │ ├── storyview_page.dart │ │ └── mainpage.dart │ ├── splashscreen.dart │ ├── onboarding │ │ ├── onboarding_pictures.dart │ │ ├── onboarding_location.dart │ │ ├── onboarding_first.dart │ │ ├── onboardinng.dart │ │ ├── onboarding_email.dart │ │ ├── onboarding_specifics.dart │ │ └── onboarding_bio.dart │ ├── homepage.dart │ └── signin.dart ├── instances │ └── login_status.dart ├── authentications_bloc │ ├── authentication_event.dart │ ├── blocdelegate.dart │ ├── authentication_state.dart │ ├── cubits │ │ ├── signup_state.dart │ │ └── signup_cubit.dart │ └── auth_bloc.dart ├── validators │ └── validators.dart ├── animations │ ├── fadeinanimation.dart │ ├── disliked.dart │ └── liked.dart ├── custompaints │ └── circular_progress.dart ├── models │ ├── chat.dart │ ├── usersmatch.dart │ └── messages.dart ├── providers │ └── userdata.dart └── main.dart ├── web ├── favicon.png ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png ├── manifest.json └── index.html ├── assets ├── images │ ├── ad.png │ ├── bell.png │ ├── chat.png │ ├── list.png │ ├── man.jpg │ ├── connect.png │ ├── loves.png │ ├── search.png │ ├── briefcase.png │ ├── verified.png │ ├── categories.png │ ├── dating_app1.jpg │ ├── dating_app2.jpg │ ├── dating_app3.jpg │ ├── search_icon.png │ ├── discover_logo.png │ └── icons8-romance-50.png └── svgs │ ├── chat_icon.svg │ ├── chat_active_icon.svg │ ├── explore_icon.svg │ ├── account_icon.svg │ ├── account_active_icon.svg │ ├── thunder_icon.svg │ ├── star_icon.svg │ ├── refresh_icon.svg │ ├── close_icon.svg │ ├── like_icon.svg │ ├── explore_active_icon.svg │ └── likes_icon.svg ├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── values-night │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── tiki │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── google-services.json │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle └── build.gradle ├── .metadata ├── .gitignore ├── test └── widget_test.dart ├── analysis_options.yaml ├── README.md └── pubspec.yaml /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/respositories/respositories.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: unnecessary_null_comparison 2 | 3 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/web/favicon.png -------------------------------------------------------------------------------- /assets/images/ad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/ad.png -------------------------------------------------------------------------------- /assets/images/bell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/bell.png -------------------------------------------------------------------------------- /assets/images/chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/chat.png -------------------------------------------------------------------------------- /assets/images/list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/list.png -------------------------------------------------------------------------------- /assets/images/man.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/man.jpg -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/web/icons/Icon-512.png -------------------------------------------------------------------------------- /assets/images/connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/connect.png -------------------------------------------------------------------------------- /assets/images/loves.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/loves.png -------------------------------------------------------------------------------- /assets/images/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/search.png -------------------------------------------------------------------------------- /assets/images/briefcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/briefcase.png -------------------------------------------------------------------------------- /assets/images/verified.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/verified.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /assets/images/categories.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/categories.png -------------------------------------------------------------------------------- /assets/images/dating_app1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/dating_app1.jpg -------------------------------------------------------------------------------- /assets/images/dating_app2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/dating_app2.jpg -------------------------------------------------------------------------------- /assets/images/dating_app3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/dating_app3.jpg -------------------------------------------------------------------------------- /assets/images/search_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/search_icon.png -------------------------------------------------------------------------------- /assets/images/discover_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/discover_logo.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /assets/images/icons8-romance-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/assets/images/icons8-romance-50.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/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/renealexander616/Dating-App/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /lib/respositories/baseloadusersrepo.dart: -------------------------------------------------------------------------------- 1 | import 'package:tiki/models/user.dart'; 2 | 3 | abstract class BaseUsersRepo { 4 | Stream> getUsers(); 5 | } 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/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/renealexander616/Dating-App/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/renealexander616/Dating-App/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /lib/widgets/extensions.dart: -------------------------------------------------------------------------------- 1 | extension StringExtension on String { 2 | String capitalize() { 3 | return "${this[0].toUpperCase()}${this.substring(1).toLowerCase()}"; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /lib/respositories/base_storage_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:image_picker/image_picker.dart'; 2 | 3 | abstract class BaseStroageRepository { 4 | Future uploadImage(XFile image); 5 | } 6 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/tiki/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.tiki 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renealexander616/Dating-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/respositories/base_database_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:tiki/models/user.dart'; 2 | 3 | abstract class BaseDatabaseRepository { 4 | Stream getUser(); 5 | Future updateUserPictures(String imagePath); 6 | } 7 | -------------------------------------------------------------------------------- /assets/svgs/chat_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/svgs/chat_active_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /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.1.1-all.zip 7 | -------------------------------------------------------------------------------- /lib/respositories/auth_repositoties.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart' as auth; 2 | 3 | abstract class BaseAuthRepository { 4 | Stream get user; 5 | Future signInWithEmailAndPassword({ 6 | String email, 7 | String password, 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/constatns/colors.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AppColors { 4 | static const Color primary = Color(0xFF00BFA5); 5 | static const Color primaryLight = Color(0xFF00FFA5); 6 | static const backgroungColor = Color(0xFFF5F5F5); 7 | static const textfieldGrey = Color(0xFFE0E0E0); 8 | } 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 4cc385b4b84ac2f816d939a49ea1f328c4e0b48e 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /lib/pages/tabs/profile.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Profile extends StatefulWidget { 4 | const Profile({Key? key}) : super(key: key); 5 | 6 | @override 7 | _ProfileState createState() => _ProfileState(); 8 | } 9 | 10 | class _ProfileState extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Container(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /assets/svgs/explore_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /lib/pages/tabs/matching.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Matching extends StatefulWidget { 4 | const Matching({Key? key}) : super(key: key); 5 | 6 | @override 7 | _MatchingState createState() => _MatchingState(); 8 | } 9 | 10 | class _MatchingState extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Container(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/respositories/bloc/auth_event.dart: -------------------------------------------------------------------------------- 1 | part of 'auth_bloc.dart'; 2 | 3 | abstract class AuthEvent extends Equatable { 4 | const AuthEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class AuthUserChanged extends AuthEvent { 11 | final auth.User user; 12 | 13 | const AuthUserChanged({ 14 | required this.user, 15 | }); 16 | 17 | @override 18 | List get props => [user]; 19 | } 20 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/respositories/bloc/image_event.dart: -------------------------------------------------------------------------------- 1 | part of 'image_bloc.dart'; 2 | 3 | abstract class ImageEvent extends Equatable { 4 | const ImageEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class LoadImage extends ImageEvent {} 11 | 12 | class UpdateImages extends ImageEvent { 13 | final List imageUrls; 14 | 15 | const UpdateImages({required this.imageUrls}); 16 | 17 | @override 18 | List get props => [imageUrls]; 19 | } 20 | -------------------------------------------------------------------------------- /lib/respositories/bloc/image_state.dart: -------------------------------------------------------------------------------- 1 | part of 'image_bloc.dart'; 2 | 3 | abstract class ImageState extends Equatable { 4 | const ImageState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class ImagesLoading extends ImageState {} 11 | 12 | class ImagesLoaded extends ImageState { 13 | final List imageUrls; 14 | const ImagesLoaded({this.imageUrls = const []}); 15 | 16 | @override 17 | List get props => [imageUrls]; 18 | } 19 | -------------------------------------------------------------------------------- /lib/instances/login_status.dart: -------------------------------------------------------------------------------- 1 | import 'package:shared_preferences/shared_preferences.dart'; 2 | 3 | class Instances { 4 | static void saveLoginStatus(String status) async { 5 | SharedPreferences prefs = await SharedPreferences.getInstance(); 6 | prefs.setString('login', status); 7 | } 8 | 9 | static void getLoginStatus(bool status) async { 10 | SharedPreferences prefs = await SharedPreferences.getInstance(); 11 | status = prefs.getBool('login')!; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /assets/svgs/account_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /assets/svgs/account_active_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/widgets/header.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:google_fonts/google_fonts.dart'; 3 | 4 | class CustomTextHeader extends StatelessWidget { 5 | final String text; 6 | 7 | const CustomTextHeader({ 8 | Key? key, 9 | required this.text, 10 | }) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Text(text, 15 | style: GoogleFonts.aBeeZee( 16 | fontSize: 16, 17 | fontWeight: FontWeight.w500, 18 | )); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } -------------------------------------------------------------------------------- /assets/svgs/thunder_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/respositories/bloc/serachstate.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:tiki/models/user.dart'; 3 | 4 | abstract class SearchState extends Equatable { 5 | const SearchState(); 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class InitialSearchState extends SearchState {} 11 | 12 | class LoadingState extends SearchState {} 13 | 14 | class LoadUserState extends SearchState { 15 | final User user, currentUser; 16 | 17 | LoadUserState(this.user, this.currentUser); 18 | 19 | @override 20 | List get props => [user, currentUser]; 21 | } 22 | -------------------------------------------------------------------------------- /lib/authentications_bloc/authentication_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class AuthenticationEvent extends Equatable { 4 | const AuthenticationEvent(); 5 | @override 6 | List get props => []; 7 | } 8 | 9 | class AppStarted extends AuthenticationEvent { 10 | @override 11 | String toString() => 'AppStarted'; 12 | } 13 | 14 | class LoggedIn extends AuthenticationEvent { 15 | @override 16 | String toString() => 'LoggedIn'; 17 | } 18 | 19 | class LoggedOut extends AuthenticationEvent { 20 | @override 21 | String toString() => 'LoggedOut'; 22 | } 23 | -------------------------------------------------------------------------------- /lib/validators/validators.dart: -------------------------------------------------------------------------------- 1 | class Validators { 2 | static final RegExp _passwordReg = 3 | RegExp(r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!@#\$&*~]).{8,}$'); 4 | 5 | static final RegExp _eimalReg = RegExp( 6 | r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'); 7 | 8 | static isValidEmail(String email) { 9 | return _eimalReg.hasMatch(email); 10 | } 11 | 12 | static isVaildPassword(String password) { 13 | return _passwordReg.hasMatch(password); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/pages/splashscreen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:tiki/constatns/colors.dart'; 3 | 4 | class SplashScreen extends StatefulWidget { 5 | const SplashScreen({Key? key}) : super(key: key); 6 | 7 | @override 8 | _SplashScreenState createState() => _SplashScreenState(); 9 | } 10 | 11 | class _SplashScreenState extends State { 12 | @override 13 | Widget build(BuildContext context) { 14 | return const Scaffold( 15 | backgroundColor: AppColors.backgroungColor, 16 | body: Center( 17 | child: Text('Splash Screen'), 18 | ), 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /assets/svgs/star_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /assets/svgs/refresh_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/authentications_bloc/blocdelegate.dart: -------------------------------------------------------------------------------- 1 | // import 'package:flutter_bloc/flutter_bloc.dart'; 2 | 3 | // class SimpleBlocDelegate extends BlocDelegate { 4 | // @override 5 | // void onEvent(Bloc bloc, Object event) { 6 | // super.onEvent(bloc, event); 7 | // print(event); 8 | // } 9 | 10 | // @override 11 | // void onError(Bloc bloc, Object error, StackTrace stackTrace) { 12 | // super.onError(bloc, error, stackTrace); 13 | // print(error); 14 | // } 15 | 16 | // @override 17 | // void onTransition(Bloc bloc, Transition transition) { 18 | // super.onTransition(bloc, transition); 19 | // print(transition); 20 | // } 21 | // } 22 | -------------------------------------------------------------------------------- /assets/svgs/close_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/animations/fadeinanimation.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; 3 | 4 | extension AnimatedWidgetExtension on Widget { 5 | fadeInList(int index, bool isVertical) { 6 | double offset = 50.0; 7 | return AnimationConfiguration.staggeredList( 8 | position: index, 9 | duration: const Duration(milliseconds: 500), 10 | child: SlideAnimation( 11 | horizontalOffset: isVertical ? 0.0 : offset, 12 | verticalOffset: !isVertical ? 0.0 : offset, 13 | child: FadeInAnimation( 14 | child: this, 15 | ), 16 | ), 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/ephemeral/ 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /lib/widgets/check_box.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:google_fonts/google_fonts.dart'; 3 | 4 | class CustomCheckbox extends StatelessWidget { 5 | final String text; 6 | 7 | const CustomCheckbox({ 8 | Key? key, 9 | required this.text, 10 | }) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Row( 15 | children: [ 16 | Checkbox( 17 | value: false, 18 | onChanged: (bool? newValue) {}, 19 | ), 20 | Text( 21 | text, 22 | style: GoogleFonts.aBeeZee( 23 | fontSize: 16, 24 | ), 25 | ), 26 | ], 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /assets/svgs/like_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/respositories/bloc/auth_state.dart: -------------------------------------------------------------------------------- 1 | part of 'auth_bloc.dart'; 2 | 3 | enum AuthStatus { 4 | unknown, 5 | authenticated, 6 | unauthenticated, 7 | } 8 | 9 | class AuthState extends Equatable { 10 | final AuthStatus status; 11 | final auth.User? user; 12 | 13 | const AuthState._({ 14 | this.status = AuthStatus.unknown, 15 | this.user, 16 | }); 17 | const AuthState.unknown() : this._(); 18 | const AuthState.authenticated({required auth.User user}) 19 | : this._( 20 | status: AuthStatus.authenticated, 21 | user: user, 22 | ); 23 | 24 | const AuthState.unauthenticated() 25 | : this._(status: AuthStatus.unauthenticated); 26 | @override 27 | List get props => [status, user]; 28 | } 29 | -------------------------------------------------------------------------------- /lib/respositories/bloc/swipebloc_state.dart: -------------------------------------------------------------------------------- 1 | part of 'swipebloc_bloc.dart'; 2 | 3 | abstract class SwipeState extends Equatable { 4 | const SwipeState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class SwipeLoading extends SwipeState {} 11 | 12 | class SwipeLoaded extends SwipeState { 13 | final List users; 14 | 15 | const SwipeLoaded({ 16 | this.users = const [], 17 | }); 18 | 19 | @override 20 | List get props => [users]; 21 | } 22 | 23 | class SwipeError extends SwipeState {} 24 | 25 | class SwipeEmpty extends SwipeState { 26 | final String message; 27 | 28 | const SwipeEmpty({ 29 | required this.message, 30 | }); 31 | 32 | @override 33 | List get props => [message]; 34 | } 35 | -------------------------------------------------------------------------------- /lib/pages/tabs/storyview_page.dart: -------------------------------------------------------------------------------- 1 | // import 'package:flutter/material.dart'; 2 | // import "package:story_view/story_view.dart"; 3 | // import 'package:tiki/models/user.dart'; 4 | 5 | // class StroyViewPage extends StatefulWidget { 6 | // final User user; 7 | // const StroyViewPage({ Key? key, required this.user}) : super(key: key); 8 | 9 | // @override 10 | // _StroyViewPageState createState() => _StroyViewPageState(); 11 | // } 12 | 13 | // class _StroyViewPageState extends State { 14 | // final storyController = StoryController(); 15 | 16 | 17 | // @override 18 | // Widget build(BuildContext context) { 19 | // return StoryView( 20 | // controller: storyController, 21 | // storyItems: 22 | 23 | 24 | // ); 25 | // } 26 | // } -------------------------------------------------------------------------------- /assets/svgs/explore_active_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.6.0' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.google.gms:google-services:4.3.3' 10 | classpath 'com.android.tools.build:gradle:4.0.1' 11 | classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.2' 12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 13 | } 14 | } 15 | 16 | allprojects { 17 | 18 | repositories { 19 | google() 20 | mavenCentral() 21 | } 22 | } 23 | 24 | rootProject.buildDir = '../build' 25 | subprojects { 26 | project.buildDir = "${rootProject.buildDir}/${project.name}" 27 | project.evaluationDependsOn(':app') 28 | } 29 | 30 | task clean(type: Delete) { 31 | delete rootProject.buildDir 32 | } 33 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 9.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/respositories/baseusers.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:cloud_firestore/cloud_firestore.dart'; 4 | import 'package:firebase_auth/firebase_auth.dart' as auth; 5 | import 'package:tiki/models/user.dart'; 6 | import 'package:tiki/respositories/baseloadusersrepo.dart'; 7 | 8 | class Usersdata extends BaseUsersRepo { 9 | final FirebaseFirestore _firestore; 10 | 11 | Usersdata({FirebaseFirestore? firestore}) 12 | : _firestore = firestore ?? FirebaseFirestore.instance; 13 | 14 | @override 15 | Stream> getUsers() { 16 | var user = auth.FirebaseAuth.instance.currentUser; 17 | return _firestore 18 | .collection('users') 19 | .where('email', isNotEqualTo: user!.email) 20 | .snapshots() 21 | .map((snapshot) { 22 | return snapshot.docs.map((doc) { 23 | return User.fromSnapshot(doc); 24 | }).toList(); 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/respositories/bloc/swipebloc_event.dart: -------------------------------------------------------------------------------- 1 | part of 'swipebloc_bloc.dart'; 2 | 3 | abstract class SwipeEvent extends Equatable { 4 | const SwipeEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class LoadedSwipe extends SwipeEvent {} 11 | 12 | class LoadUsersEvent extends SwipeEvent { 13 | final List users; 14 | 15 | const LoadUsersEvent( 16 | this.users, 17 | ); 18 | 19 | @override 20 | List get props => [users]; 21 | } 22 | 23 | class SwipeLeftEvent extends SwipeEvent { 24 | final User user; 25 | 26 | const SwipeLeftEvent({ 27 | required this.user, 28 | }); 29 | 30 | @override 31 | List get props => [user]; 32 | } 33 | 34 | class SwipeRightEvent extends SwipeEvent { 35 | final User user; 36 | 37 | const SwipeRightEvent({ 38 | required this.user, 39 | }); 40 | 41 | @override 42 | List get props => [user]; 43 | } 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tiki", 3 | "short_name": "tiki", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "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/authentications_bloc/authentication_state.dart: -------------------------------------------------------------------------------- 1 | // import 'package:equatable/equatable.dart'; 2 | 3 | // abstract class AuthenticationState extends Equatable { 4 | // const AuthenticationState(); 5 | // @override 6 | // List get props => []; 7 | // } 8 | 9 | // class Uinitialized extends AuthenticationState {} 10 | 11 | // class Authenticated extends AuthenticationState { 12 | // final String userId; 13 | // const Authenticated(this.userId); 14 | 15 | // @override 16 | // List get props => [userId]; 17 | 18 | // @override 19 | // String toString() => 'Authenticated { userId: $userId }'; 20 | // } 21 | 22 | // class Unauthenticated extends AuthenticationState { 23 | // @override 24 | // String toString() => 'Unauthenticated'; 25 | 26 | // @override 27 | // List get props => []; 28 | // } 29 | 30 | // class AuthenticatedButNotSet extends AuthenticationState { 31 | // final String userId; 32 | // const AuthenticatedButNotSet(this.userId); 33 | // @override 34 | // List get props => [userId]; 35 | // } 36 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lib/respositories/bloc/search_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class SearchEvent extends Equatable { 4 | @override 5 | List get props => []; 6 | } 7 | 8 | class LoadUserEvent extends SearchEvent { 9 | final String userId; 10 | 11 | LoadUserEvent({required this.userId}); 12 | 13 | @override 14 | List get props => [userId]; 15 | } 16 | 17 | class SearchInitial extends SearchEvent {} 18 | 19 | class SelectUserEvent extends SearchEvent { 20 | final String currentUserId, selectedUserId, name, photoUrl; 21 | 22 | SelectUserEvent( 23 | {required this.currentUserId, 24 | required this.name, 25 | required this.photoUrl, 26 | required this.selectedUserId}); 27 | 28 | @override 29 | List get props => [currentUserId, selectedUserId, name, photoUrl]; 30 | } 31 | 32 | class PassUserEvent extends SearchEvent { 33 | final String currentUserId, selectedUserId; 34 | 35 | PassUserEvent(this.currentUserId, this.selectedUserId); 36 | 37 | @override 38 | List get props => [currentUserId, selectedUserId]; 39 | } 40 | -------------------------------------------------------------------------------- /lib/widgets/custom_textfield.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:google_fonts/google_fonts.dart'; 3 | 4 | class CustomTextField extends StatelessWidget { 5 | final String hint; 6 | final IconData icon; 7 | final Function(String)? onChanged; 8 | 9 | const CustomTextField({ 10 | Key? key, 11 | required this.hint, 12 | required this.icon, 13 | this.onChanged, 14 | }) : super(key: key); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return TextField( 19 | decoration: InputDecoration( 20 | filled: true, 21 | fillColor: Colors.white, 22 | hintText: hint, 23 | suffixIcon: Icon(icon), 24 | hintStyle: GoogleFonts.aBeeZee( 25 | fontSize: 13, 26 | color: Colors.grey, 27 | ), 28 | focusedBorder: const OutlineInputBorder( 29 | borderSide: BorderSide(color: Colors.white), 30 | ), 31 | enabledBorder: const UnderlineInputBorder( 32 | borderSide: BorderSide(color: Colors.white), 33 | ), 34 | ), 35 | onChanged: onChanged, 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/custompaints/circular_progress.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:math' as math; 3 | 4 | class CustomTimerPainter extends CustomPainter { 5 | CustomTimerPainter({ 6 | required this.animation, 7 | required this.backgroundColor, 8 | required this.color, 9 | }) : super(repaint: animation); 10 | 11 | final Animation animation; 12 | final Color backgroundColor, color; 13 | 14 | @override 15 | void paint(Canvas canvas, Size size) { 16 | Paint paint = Paint() 17 | ..color = backgroundColor 18 | ..strokeWidth = 6.0 19 | ..strokeCap = StrokeCap.butt 20 | ..style = PaintingStyle.stroke; 21 | 22 | canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint); 23 | paint.color = color; 24 | double progress = (1.0 - animation.value) * 4 * math.pi; 25 | canvas.drawArc(Offset.zero & size, math.pi * 1.5, progress, false, paint); 26 | } 27 | 28 | @override 29 | bool shouldRepaint(CustomTimerPainter old) { 30 | return animation.value / 5 != old.animation.value || 31 | color != old.color || 32 | backgroundColor != old.backgroundColor; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/respositories/databerepository.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | import 'package:firebase_auth/firebase_auth.dart' as auth; 3 | import 'package:tiki/models/user.dart'; 4 | import 'package:tiki/respositories/base_database_repository.dart'; 5 | import 'package:tiki/respositories/storage_repository.dart'; 6 | 7 | class DatabaseRepository extends BaseDatabaseRepository { 8 | final FirebaseFirestore _firestore = FirebaseFirestore.instance; 9 | final auth.FirebaseAuth firebaseAuth = auth.FirebaseAuth.instance; 10 | 11 | @override 12 | Stream getUser() { 13 | return _firestore 14 | .collection('users') 15 | .doc(firebaseAuth.currentUser!.email) 16 | .snapshots() 17 | .map((snapshot) => User.fromSnapshot(snapshot)); 18 | } 19 | 20 | @override 21 | Future updateUserPictures(String imageName) async { 22 | String getdownloadUrl = await StorageRepository().getImageUrl(imageName); 23 | return _firestore 24 | .collection('users') 25 | .doc(firebaseAuth.currentUser!.email) 26 | .update({ 27 | 'imageUrl': FieldValue.arrayUnion([getdownloadUrl]) 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/respositories/storage_repository.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:firebase_auth/firebase_auth.dart'; 4 | import 'package:image_picker/image_picker.dart'; 5 | import 'package:firebase_storage/firebase_storage.dart' as firebase_storage; 6 | import 'package:tiki/respositories/base_storage_repository.dart'; 7 | import 'package:tiki/respositories/databerepository.dart'; 8 | 9 | class StorageRepository extends BaseStroageRepository { 10 | final FirebaseAuth _auth = FirebaseAuth.instance; 11 | final firebase_storage.FirebaseStorage storage = 12 | firebase_storage.FirebaseStorage.instance; 13 | Future uploadImage(XFile image) async { 14 | try { 15 | await storage 16 | .ref(_auth.currentUser!.email) 17 | .child(image.name) 18 | .putFile(File(image.path)) 19 | .then((p0) => DatabaseRepository().updateUserPictures(image.name)); 20 | } catch (e) { 21 | print(e); 22 | } 23 | } 24 | 25 | Future getImageUrl(String imageName) async { 26 | String downloadUrl = await storage 27 | .ref("${_auth.currentUser!.email}/$imageName") 28 | .getDownloadURL(); 29 | return downloadUrl; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // // This is a basic Flutter widget test. 2 | // // 3 | // // To perform an interaction with a widget in your test, use the WidgetTester 4 | // // utility that Flutter provides. For example, you can send tap and scroll 5 | // // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | // import 'package:flutter/material.dart'; 9 | // import 'package:flutter_test/flutter_test.dart'; 10 | 11 | // import 'package:tiki/main.dart'; 12 | 13 | // void main() { 14 | // testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // // Build our app and trigger a frame. 16 | // await tester.pumpWidget(const MyApp()); 17 | 18 | // // Verify that our counter starts at 0. 19 | // expect(find.text('0'), findsOneWidget); 20 | // expect(find.text('1'), findsNothing); 21 | 22 | // // Tap the '+' icon and trigger a frame. 23 | // await tester.tap(find.byIcon(Icons.add)); 24 | // await tester.pump(); 25 | 26 | // // Verify that our counter has incremented. 27 | // expect(find.text('0'), findsNothing); 28 | // expect(find.text('1'), findsOneWidget); 29 | // }); 30 | // } 31 | -------------------------------------------------------------------------------- /lib/respositories/bloc/auth_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:firebase_auth/firebase_auth.dart' as auth; 5 | import 'package:equatable/equatable.dart'; 6 | import 'package:tiki/respositories/mainauth.dart'; 7 | 8 | part 'auth_event.dart'; 9 | part 'auth_state.dart'; 10 | 11 | class AuthBloc extends Bloc { 12 | final AuthRepository _authRepository; 13 | StreamSubscription? _userSubscription; 14 | 15 | AuthBloc({ 16 | required AuthRepository authRepository, 17 | }) : _authRepository = authRepository, 18 | super(const AuthState.unknown()) { 19 | _userSubscription = _authRepository.user.listen( 20 | (user) => add( 21 | AuthUserChanged(user: user!), 22 | ), 23 | ); 24 | } 25 | 26 | @override 27 | Stream mapEventToState(AuthEvent event) async* { 28 | if (event is AuthUserChanged) { 29 | yield* _mapAuthUserChangedToState(event); 30 | } 31 | } 32 | 33 | Stream _mapAuthUserChangedToState(AuthUserChanged event) async* { 34 | yield AuthState.authenticated(user: event.user); 35 | } 36 | 37 | @override 38 | Future close() { 39 | _userSubscription?.cancel(); 40 | return super.close(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/constatns/app_router.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:tiki/main.dart'; 3 | import 'package:tiki/pages/onboarding/onboardinng.dart'; 4 | 5 | class AppRouter { 6 | static Route onGenerateRoute(RouteSettings settings) { 7 | print('The Route is: ${settings.name}'); 8 | 9 | switch (settings.name) { 10 | case '/': 11 | // return HomeScreen.route(); 12 | // case HomeScreen.routeName: 13 | // return HomeScreen.route(); 14 | // case UsersScreen.routeName: 15 | // return UsersScreen.route(user: settings.arguments as User); 16 | case OnboardingScreen.routeName: 17 | return OnboardingScreen.route(); 18 | // case AuthenticationWrapper.routeName: 19 | // return AuthenticationWrapper.route(); 20 | // case ProfileScreen.routeName: 21 | // return ProfileScreen.route(); 22 | // case ChatScreen.routeName: 23 | // return ChatScreen.route(userMatch: settings.arguments as UserMatch); 24 | default: 25 | return _errorRoute(); 26 | } 27 | } 28 | 29 | static Route _errorRoute() { 30 | return MaterialPageRoute( 31 | builder: (_) => Scaffold(appBar: AppBar(title: const Text('error'))), 32 | settings: const RouteSettings(name: '/error'), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/respositories/bloc/image_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:equatable/equatable.dart'; 5 | import 'package:tiki/respositories/databerepository.dart'; 6 | 7 | part 'image_event.dart'; 8 | part 'image_state.dart'; 9 | 10 | class ImageBloc extends Bloc { 11 | final DatabaseRepository _databaseRepository; 12 | StreamSubscription? databaseSubscription; 13 | 14 | ImageBloc({ 15 | required DatabaseRepository databaseRepository, 16 | }) : _databaseRepository = databaseRepository, 17 | super(ImagesLoading()); 18 | 19 | @override 20 | Stream mapEventToState(ImageEvent event) async* { 21 | if (event is ImagesLoaded) { 22 | yield* _mapLoadImagesToState(); 23 | } 24 | if (event is UpdateImages) { 25 | yield* _mapUpdateImagesToState(event); 26 | } 27 | } 28 | 29 | Stream _mapLoadImagesToState() async* { 30 | databaseSubscription?.cancel(); 31 | 32 | _databaseRepository 33 | .getUser() 34 | .listen((user) => add(UpdateImages(imageUrls: user.imageUrls ?? []))); 35 | } 36 | 37 | Stream _mapUpdateImagesToState(UpdateImages event) async* { 38 | yield ImagesLoaded(imageUrls: event.imageUrls); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/widgets/small_image.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:tiki/constatns/colors.dart'; 3 | import 'package:flutter/cupertino.dart'; 4 | 5 | class UserImageSmall extends StatelessWidget { 6 | final String url; 7 | final double height; 8 | final double width; 9 | 10 | const UserImageSmall({ 11 | Key? key, 12 | required this.url, 13 | this.height = 60, 14 | this.width = 60, 15 | }) : super(key: key); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Stack( 20 | children: [ 21 | Container( 22 | margin: const EdgeInsets.only(top: 8, right: 8), 23 | height: height, 24 | width: width, 25 | decoration: BoxDecoration( 26 | image: DecorationImage( 27 | fit: BoxFit.cover, 28 | image: NetworkImage(url), 29 | ), 30 | shape: BoxShape.circle, 31 | color: Theme.of(context).primaryColor, 32 | ), 33 | ), 34 | Positioned( 35 | bottom: 8, 36 | right: 10, 37 | child: Container( 38 | height: 12, 39 | width: 12, 40 | decoration: const BoxDecoration( 41 | color: Color.fromARGB(255, 5, 238, 64), 42 | shape: BoxShape.circle, 43 | ), 44 | ), 45 | ) 46 | ], 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /android/app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "334114304202", 4 | "project_id": "tiki-1cb3c", 5 | "storage_bucket": "tiki-1cb3c.appspot.com" 6 | }, 7 | "client": [ 8 | { 9 | "client_info": { 10 | "mobilesdk_app_id": "1:334114304202:android:224e39fc12d14b4bb2c433", 11 | "android_client_info": { 12 | "package_name": "com.example.tiki" 13 | } 14 | }, 15 | "oauth_client": [ 16 | { 17 | "client_id": "334114304202-srb97jo2dcvp0edh5mfjkc5n0b3ibskg.apps.googleusercontent.com", 18 | "client_type": 1, 19 | "android_info": { 20 | "package_name": "com.example.tiki", 21 | "certificate_hash": "93d563d942a7181610400bbe8fea41642c3f98e6" 22 | } 23 | }, 24 | { 25 | "client_id": "334114304202-hs093aad5gijbboi1jqhff0nhh94nrb2.apps.googleusercontent.com", 26 | "client_type": 3 27 | } 28 | ], 29 | "api_key": [ 30 | { 31 | "current_key": "AIzaSyCO6j_4aQJRuR5XVjAGMh_83Prjp8hmh8c" 32 | } 33 | ], 34 | "services": { 35 | "appinvite_service": { 36 | "other_platform_oauth_client": [ 37 | { 38 | "client_id": "334114304202-hs093aad5gijbboi1jqhff0nhh94nrb2.apps.googleusercontent.com", 39 | "client_type": 3 40 | } 41 | ] 42 | } 43 | } 44 | } 45 | ], 46 | "configuration_version": "1" 47 | } -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | tiki 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dating App Made with Flutter & Firebase :smile: [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) [![Twitter Follow](https://img.shields.io/twitter/follow/MortyWentMia.svg?style=social)](https://twitter.com/MortyWentMia) 2 | 3 | 4 | ## you can also buy me coffee 5 | > 6 | 7 | 11 | 12 | ### 💻 Requirements :alien: 13 | 14 | * Any Operating System (MacOS, Linux, Windows) 15 | * Any IDE with Flutter SDK installed (Android Studio, VSCode etc) 16 | * A little knowledge of Dart and Flutter 17 | 18 | ### 👨‍💻 Author 19 | 20 | Ui developed by DamiFlutter [![Twitter Follow](https://img.shields.io/twitter/follow/MortyWentMia.svg?style=social)](https://twitter.com/MortyWentMia) 21 | 22 | # Screenshot: 23 | 24 | 25 | 26 | 27 | # Leave a star on the repository if you like what you see. 28 | ## Getting Started 29 | 30 | This project is a starting point for a Flutter application. 31 | 32 | A few resources to get you started if this is your first Flutter project: 33 | 34 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 35 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 36 | 37 | 38 | -------------------------------------------------------------------------------- /lib/models/chat.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:tiki/models/messages.dart'; 3 | 4 | class Chat extends Equatable { 5 | final int id; 6 | final int userId; 7 | final int matchedUserId; 8 | final List messages; 9 | 10 | Chat({ 11 | required this.id, 12 | required this.userId, 13 | required this.matchedUserId, 14 | required this.messages, 15 | }); 16 | 17 | @override 18 | List get props => [id, userId, matchedUserId, messages]; 19 | 20 | static List chats = [ 21 | Chat( 22 | id: 1, 23 | userId: 1, 24 | matchedUserId: 2, 25 | messages: Message.messages 26 | .where((message) => 27 | (message.senderId == 1 && message.receiverId == 2) || 28 | (message.senderId == 2 && message.receiverId == 1)) 29 | .toList(), 30 | ), 31 | Chat( 32 | id: 2, 33 | userId: 1, 34 | matchedUserId: 3, 35 | messages: Message.messages 36 | .where((message) => 37 | (message.senderId == 1 && message.receiverId == 3) || 38 | (message.senderId == 3 && message.receiverId == 1)) 39 | .toList(), 40 | ), 41 | Chat( 42 | id: 3, 43 | userId: 1, 44 | matchedUserId: 5, 45 | messages: Message.messages 46 | .where((message) => 47 | (message.senderId == 1 && message.receiverId == 5) || 48 | (message.senderId == 5 && message.receiverId == 1)) 49 | .toList(), 50 | ), 51 | Chat( 52 | id: 4, 53 | userId: 1, 54 | matchedUserId: 6, 55 | messages: Message.messages 56 | .where((message) => 57 | (message.senderId == 1 && message.receiverId == 6) || 58 | (message.senderId == 6 && message.receiverId == 1)) 59 | .toList(), 60 | ), 61 | ]; 62 | } 63 | -------------------------------------------------------------------------------- /lib/animations/disliked.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DislikedWidget extends StatefulWidget { 4 | final Widget child; 5 | final bool isAnimation; 6 | final Duration duration; 7 | final VoidCallback? onEnd; 8 | const DislikedWidget( 9 | {Key? key, 10 | required this.child, 11 | required this.isAnimation, 12 | required this.onEnd, 13 | this.duration = const Duration(milliseconds: 150)}) 14 | : super(key: key); 15 | 16 | @override 17 | _DislikedWidgetState createState() => _DislikedWidgetState(); 18 | } 19 | 20 | class _DislikedWidgetState extends State 21 | with SingleTickerProviderStateMixin { 22 | late AnimationController _controller; 23 | late Animation scale; 24 | @override 25 | void initState() { 26 | // TODO: implement initState 27 | super.initState(); 28 | final halfDuration = widget.duration.inMilliseconds ~/ 2; 29 | _controller = AnimationController( 30 | vsync: this, 31 | duration: Duration(milliseconds: halfDuration), 32 | ); 33 | scale = Tween(begin: 1, end: 1.2).animate(_controller); 34 | } 35 | 36 | @override 37 | void didUpdateWidget(DislikedWidget oldWidget) { 38 | super.didUpdateWidget(oldWidget); 39 | if (widget.isAnimation != oldWidget.isAnimation) { 40 | animate(); 41 | } 42 | } 43 | 44 | Future animate() async { 45 | if (widget.isAnimation) { 46 | await _controller.forward(); 47 | await _controller.reverse(); 48 | await Future.delayed(const Duration(milliseconds: 400)); 49 | if (widget.onEnd != null) { 50 | widget.onEnd!(); 51 | } 52 | } 53 | } 54 | 55 | @override 56 | void dispose() { 57 | super.dispose(); 58 | _controller.dispose(); 59 | } 60 | 61 | @override 62 | Widget build(BuildContext context) => 63 | ScaleTransition(scale: scale, child: widget.child); 64 | } 65 | -------------------------------------------------------------------------------- /lib/animations/liked.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class HeartAnimationWidget extends StatefulWidget { 4 | final Widget child; 5 | final bool isAnimation; 6 | final Duration duration; 7 | final VoidCallback? onEnd; 8 | const HeartAnimationWidget( 9 | {Key? key, 10 | required this.child, 11 | required this.isAnimation, 12 | required this.onEnd, 13 | this.duration = const Duration(milliseconds: 150)}) 14 | : super(key: key); 15 | 16 | @override 17 | _HeartAnimationWidgetState createState() => _HeartAnimationWidgetState(); 18 | } 19 | 20 | class _HeartAnimationWidgetState extends State 21 | with SingleTickerProviderStateMixin { 22 | late AnimationController _controller; 23 | late Animation scale; 24 | @override 25 | void initState() { 26 | // TODO: implement initState 27 | super.initState(); 28 | final halfDuration = widget.duration.inMilliseconds ~/ 2; 29 | _controller = AnimationController( 30 | vsync: this, 31 | duration: Duration(milliseconds: halfDuration), 32 | ); 33 | scale = Tween(begin: 1, end: 1.2).animate(_controller); 34 | } 35 | 36 | @override 37 | void didUpdateWidget(HeartAnimationWidget oldWidget) { 38 | super.didUpdateWidget(oldWidget); 39 | if (widget.isAnimation != oldWidget.isAnimation) { 40 | animate(); 41 | } 42 | } 43 | 44 | Future animate() async { 45 | if (widget.isAnimation) { 46 | await _controller.forward(); 47 | await _controller.reverse(); 48 | await Future.delayed(const Duration(milliseconds: 400)); 49 | if (widget.onEnd != null) { 50 | widget.onEnd!(); 51 | } 52 | } 53 | } 54 | 55 | @override 56 | void dispose() { 57 | super.dispose(); 58 | _controller.dispose(); 59 | } 60 | 61 | @override 62 | Widget build(BuildContext context) => 63 | ScaleTransition(scale: scale, child: widget.child); 64 | } 65 | -------------------------------------------------------------------------------- /lib/widgets/choicebtn.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_svg/flutter_svg.dart'; 3 | 4 | class ChoiceButton extends StatelessWidget { 5 | final double width; 6 | final double height; 7 | final bool hasGradient; 8 | final bool isSvg; 9 | final double size; 10 | final IconData icon; 11 | final Color color; 12 | final String? path; 13 | final Color? linear1; 14 | final Color? linear2; 15 | const ChoiceButton( 16 | {Key? key, 17 | required this.width, 18 | required this.height, 19 | required this.color, 20 | this.path, 21 | required this.size, 22 | this.isSvg = false, 23 | this.linear1, 24 | this.linear2, 25 | required this.hasGradient, 26 | required this.icon}) 27 | : super(key: key); 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return Container( 32 | height: height, 33 | width: width, 34 | child: isSvg 35 | ? SvgPicture.asset( 36 | path ?? '', 37 | height: 25, 38 | width: 25, 39 | fit: BoxFit.scaleDown, 40 | ) 41 | : Icon( 42 | icon, 43 | size: size, 44 | color: color, 45 | ), 46 | decoration: BoxDecoration( 47 | gradient: hasGradient 48 | ? LinearGradient( 49 | begin: Alignment.topCenter, 50 | end: Alignment.bottomCenter, 51 | colors: [ 52 | linear1!, 53 | linear2!, 54 | ]) 55 | : null, 56 | boxShadow: [ 57 | BoxShadow( 58 | color: Colors.grey.withAlpha(50), 59 | spreadRadius: 4, 60 | blurRadius: 4, 61 | offset: const Offset(0, 3), 62 | ) 63 | ], 64 | shape: BoxShape.circle, 65 | color: Colors.white, 66 | ), 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/authentications_bloc/cubits/signup_state.dart: -------------------------------------------------------------------------------- 1 | part of 'signup_cubit.dart'; 2 | 3 | enum SignupStatus { initial, submitting, success, error } 4 | 5 | class SignupState extends Equatable { 6 | final String email; 7 | final String password; 8 | final String age; 9 | final String username; 10 | final String gender; 11 | final SignupStatus status; 12 | final String location; 13 | final String bio; 14 | final List interest; 15 | 16 | bool get isFormValid => email.isNotEmpty && password.isNotEmpty; 17 | 18 | const SignupState({ 19 | required this.email, 20 | required this.gender, 21 | required this.password, 22 | required this.age, 23 | required this.bio, 24 | required this.username, 25 | required this.location, 26 | required this.interest, 27 | required this.status, 28 | }); 29 | 30 | factory SignupState.initial() { 31 | return const SignupState( 32 | email: '', 33 | gender: '', 34 | age: '', 35 | password: '', 36 | bio: '', 37 | username: '', 38 | location: '', 39 | interest: [], 40 | status: SignupStatus.initial, 41 | ); 42 | } 43 | 44 | @override 45 | bool get stringify => true; 46 | 47 | @override 48 | List get props => 49 | [email, password, status, age, gender, bio, interest, location, username]; 50 | 51 | SignupState copyWith({ 52 | String? email, 53 | String? password, 54 | SignupStatus? status, 55 | String? age, 56 | String? gender, 57 | String? bio, 58 | String? username, 59 | List? interest, 60 | String? location, 61 | }) { 62 | return SignupState( 63 | email: email ?? this.email, 64 | password: password ?? this.password, 65 | gender: gender ?? this.gender, 66 | status: status ?? this.status, 67 | username: username ?? this.username, 68 | location: location ?? this.location, 69 | bio: bio ?? this.bio, 70 | interest: interest ?? this.interest, 71 | age: age ?? this.age, 72 | ); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lib/authentications_bloc/auth_bloc.dart: -------------------------------------------------------------------------------- 1 | // import 'dart:async'; 2 | // import 'package:bloc/bloc.dart'; 3 | // import 'package:tiki/authentications_bloc/authentication_event.dart'; 4 | // import 'package:tiki/authentications_bloc/authentication_state.dart'; 5 | // import 'package:tiki/respositories/respositories.dart'; 6 | 7 | // class AuthenticationBloc 8 | // extends Bloc { 9 | // final Userrespository _userrespository; 10 | 11 | // AuthenticationBloc({required Userrespository userrespository}) 12 | // : _userrespository = userrespository; 13 | 14 | // AuthenticationState get initialState => Unauthenticated(); 15 | 16 | // @override 17 | // Stream mapEventToState( 18 | // AuthenticationEvent event, 19 | // ) async* { 20 | // if (event is AppStarted) { 21 | // yield* _mapAppStartedToState(); 22 | // } else if (event is LoggedIn) { 23 | // yield* _mapLoggedInToState(); 24 | // } else if (event is LoggedOut) { 25 | // yield* _mapLoggedOutToState(); 26 | // } 27 | // } 28 | 29 | // Stream _mapAppStartedToState() async* { 30 | // try { 31 | // final isSignedIn = await _userrespository.isSIgnedIn(); 32 | // if (isSignedIn) { 33 | // final uid = await _userrespository.getUser(); 34 | 35 | // final isFirstTime = await _userrespository.isFirstTime(uid); 36 | // if (isFirstTime ?? true) { 37 | // yield AuthenticatedButNotSet(uid); 38 | // } else { 39 | // yield Authenticated(uid); 40 | // } 41 | // } else { 42 | // yield Unauthenticated(); 43 | // } 44 | // } catch (e) { 45 | // yield Unauthenticated(); 46 | // } 47 | // } 48 | 49 | // Stream _mapLoggedInToState() async* { 50 | // final isFirstTime = 51 | // await _userrespository.isFirstTime(await _userrespository.getUser()); 52 | // if (isFirstTime ?? true) { 53 | // yield AuthenticatedButNotSet(await _userrespository.getUser()); 54 | // } else { 55 | // yield Authenticated(await _userrespository.getUser()); 56 | // } 57 | // } 58 | 59 | // Stream _mapLoggedOutToState() async* { 60 | // yield Unauthenticated(); 61 | // _userrespository.signOut(); 62 | // } 63 | // } 64 | -------------------------------------------------------------------------------- /lib/models/usersmatch.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:tiki/models/chat.dart'; 3 | import 'package:tiki/models/user.dart'; 4 | 5 | class UserMatch extends Equatable { 6 | final int id; 7 | final int userId; 8 | final User matchedUser; 9 | final List? chat; 10 | 11 | const UserMatch({ 12 | required this.id, 13 | required this.userId, 14 | required this.matchedUser, 15 | required this.chat, 16 | }); 17 | 18 | @override 19 | List get props => [id, userId, matchedUser]; 20 | 21 | static List matches = [ 22 | UserMatch( 23 | id: 1, 24 | userId: 1, 25 | matchedUser: User.users[1], 26 | chat: Chat.chats 27 | .where((chat) => chat.userId == 1 && chat.matchedUserId == 2) 28 | .toList(), 29 | ), 30 | UserMatch( 31 | id: 2, 32 | userId: 1, 33 | matchedUser: User.users[2], 34 | chat: Chat.chats 35 | .where((chat) => chat.userId == 1 && chat.matchedUserId == 3) 36 | .toList(), 37 | ), 38 | UserMatch( 39 | id: 3, 40 | userId: 1, 41 | matchedUser: User.users[3], 42 | chat: Chat.chats 43 | .where((chat) => chat.userId == 1 && chat.matchedUserId == 4) 44 | .toList(), 45 | ), 46 | UserMatch( 47 | id: 4, 48 | userId: 1, 49 | matchedUser: User.users[4], 50 | chat: Chat.chats 51 | .where((chat) => chat.userId == 1 && chat.matchedUserId == 5) 52 | .toList(), 53 | ), 54 | UserMatch( 55 | id: 5, 56 | userId: 1, 57 | matchedUser: User.users[5], 58 | chat: Chat.chats 59 | .where((chat) => chat.userId == 1 && chat.matchedUserId == 6) 60 | .toList(), 61 | ), 62 | UserMatch( 63 | id: 6, 64 | userId: 1, 65 | matchedUser: User.users[6], 66 | chat: Chat.chats 67 | .where((chat) => chat.userId == 1 && chat.matchedUserId == 7) 68 | .toList(), 69 | ), 70 | UserMatch( 71 | id: 7, 72 | userId: 1, 73 | matchedUser: User.users[7], 74 | chat: Chat.chats 75 | .where((chat) => chat.userId == 1 && chat.matchedUserId == 8) 76 | .toList(), 77 | ), 78 | UserMatch( 79 | id: 8, 80 | userId: 1, 81 | matchedUser: User.users[8], 82 | chat: Chat.chats 83 | .where((chat) => chat.userId == 1 && chat.matchedUserId == 9) 84 | .toList(), 85 | ), 86 | ]; 87 | } 88 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /lib/respositories/bloc/swipebloc_bloc.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: avoid_print 2 | import 'dart:async'; 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:equatable/equatable.dart'; 5 | import 'package:tiki/models/user.dart'; 6 | import 'package:tiki/respositories/baseusers.dart'; 7 | 8 | part 'swipebloc_event.dart'; 9 | part 'swipebloc_state.dart'; 10 | 11 | class SwipeBloc extends Bloc { 12 | final Usersdata? _baseUsersRepo; 13 | StreamSubscription? _usersSubscription; 14 | SwipeBloc({ 15 | Usersdata? baseUsersRepo, 16 | }) : _baseUsersRepo = baseUsersRepo, 17 | super(SwipeLoading()); 18 | 19 | @override 20 | Stream mapEventToState( 21 | SwipeEvent event, 22 | ) async* { 23 | if (event is LoadedSwipe) { 24 | yield* _mapLoadUsersToState(); 25 | } 26 | if (event is LoadUsersEvent) { 27 | yield* _mapUpdateProductsToState(event); 28 | } 29 | if (event is SwipeLeftEvent) { 30 | yield* _mapSwipeLeftEventToState(event, state); 31 | } 32 | if (event is SwipeRightEvent) { 33 | yield* _mapSwipeRightEventToState(event, state); 34 | } 35 | } 36 | 37 | Stream _mapLoadUsersToState() async* { 38 | _usersSubscription?.cancel(); 39 | _usersSubscription = _baseUsersRepo?.getUsers().listen( 40 | (users) => add(LoadUsersEvent(users)), 41 | ); 42 | } 43 | 44 | Stream _mapUpdateProductsToState(LoadUsersEvent event) async* { 45 | yield SwipeLoaded(users: event.users); 46 | } 47 | 48 | Stream _mapSwipeLeftEventToState( 49 | SwipeLeftEvent event, 50 | SwipeState state, 51 | ) async* { 52 | if (state is SwipeLoaded) { 53 | try { 54 | yield SwipeLoaded(users: List.from(state.users)..remove(event.user)); 55 | if (state.users.isEmpty) { 56 | yield const SwipeEmpty( 57 | message: 'There is no more user to swipe', 58 | ); 59 | } 60 | } catch (_) {} 61 | } 62 | } 63 | 64 | Stream _mapSwipeRightEventToState( 65 | SwipeRightEvent event, 66 | SwipeState state, 67 | ) async* { 68 | if (state is SwipeLoaded) { 69 | try { 70 | yield SwipeLoaded(users: List.from(state.users)..remove(event.user)); 71 | if (state.users.isEmpty) { 72 | yield const SwipeEmpty( 73 | message: 'There is no more user to swipe', 74 | ); 75 | } 76 | } catch (_) { 77 | print('error'); 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/widgets/custombtn.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | import 'package:flutter_bloc/flutter_bloc.dart'; 5 | import 'package:google_fonts/google_fonts.dart'; 6 | import 'package:shared_preferences/shared_preferences.dart'; 7 | import 'package:tiki/authentications_bloc/cubits/signup_cubit.dart'; 8 | import 'package:tiki/instances/login_status.dart'; 9 | import 'package:tiki/pages/homepage.dart'; 10 | import 'package:tiki/pages/tabs/mainpage.dart'; 11 | 12 | class CustomButton extends StatelessWidget { 13 | final TabController tabController; 14 | final String text; 15 | final void function; 16 | 17 | const CustomButton({ 18 | Key? key, 19 | required this.tabController, 20 | required this.text, 21 | this.function, 22 | }) : super(key: key); 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return DecoratedBox( 27 | decoration: BoxDecoration( 28 | borderRadius: BorderRadius.circular(5), 29 | gradient: LinearGradient( 30 | colors: [ 31 | Theme.of(context).accentColor, 32 | Theme.of(context).primaryColor, 33 | ], 34 | ), 35 | ), 36 | child: ElevatedButton( 37 | onPressed: () { 38 | if (tabController.index != 5) { 39 | tabController.animateTo(tabController.index + 1); 40 | } else { 41 | context.read().updateLocation(); 42 | Navigator.push(context, 43 | CupertinoPageRoute(builder: (context) => const MainPage())); 44 | Instances.saveLoginStatus('loggedIn'); 45 | } 46 | 47 | if (tabController.index == 2) { 48 | context.read().signUpWithCredentials(); 49 | } 50 | if (tabController.index == 3) { 51 | context.read().updateDatabase(); 52 | } 53 | if (tabController.index == 5) { 54 | context.read().updateBio(); 55 | } 56 | }, 57 | style: ElevatedButton.styleFrom( 58 | primary: Colors.transparent, 59 | elevation: 0, 60 | ), 61 | child: SizedBox( 62 | width: double.infinity, 63 | child: Center( 64 | child: Text(text, 65 | style: GoogleFonts.aBeeZee( 66 | fontSize: 15, 67 | fontWeight: FontWeight.w600, 68 | )), 69 | ), 70 | ), 71 | ), 72 | ); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 9 | 16 | 20 | 24 | 29 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /lib/providers/userdata.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | import 'package:firebase_auth/firebase_auth.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class UserData extends ChangeNotifier { 6 | String? _username; 7 | String? imageUrl; 8 | String? age; 9 | List? interests; 10 | var currentUser = FirebaseAuth.instance.currentUser; 11 | 12 | Future _getUser() async { 13 | FirebaseFirestore.instance 14 | .collection('users') 15 | .doc((FirebaseAuth.instance.currentUser!.email)) 16 | .get() 17 | .then((value) { 18 | _username = value.data()!['username']; 19 | imageUrl = value.data()!['imageUrl'][0]; 20 | age = value.data()!['age']; 21 | interests = value.data()!['interest']; 22 | notifyListeners(); 23 | }); 24 | } 25 | 26 | Future getData() async { 27 | return await FirebaseFirestore.instance 28 | .collection('users') 29 | .doc((FirebaseAuth.instance.currentUser!.email)) 30 | .get(); 31 | } 32 | 33 | Future logout() async { 34 | await FirebaseAuth.instance.signOut(); 35 | notifyListeners(); 36 | } 37 | 38 | Future saveLikedUser( 39 | {required String likedUsername, 40 | required String likedUserage, 41 | required List imageurls, 42 | required List likedUserInterest, 43 | required String likedUseremail, 44 | required String likedUserAddress, 45 | required String currentUsername, 46 | required String job, 47 | required List currentUserImageurls, 48 | required String currentUserAge, 49 | required List currentUserInterest, 50 | required String currentUserAddress, 51 | required String currentoccupation, 52 | required String occupation}) { 53 | return FirebaseFirestore.instance.collection('likeduser').doc().set({ 54 | 'email': FirebaseAuth.instance.currentUser!.email, 55 | 'username': currentUsername, 56 | 'imageUrl': currentUserImageurls, 57 | 'age': currentUserAge, 58 | 'job:': job, 59 | 'interest': currentUserInterest, 60 | 'address': currentUserAddress, 61 | 'occupation': currentoccupation, 62 | 'likedUsername': likedUsername, 63 | 'likedUserEmail': likedUseremail, 64 | 'likedUserage': likedUserage, 65 | 'likedUserImageUrls': imageurls, 66 | 'likedUserInterests': likedUserInterest, 67 | 'likeduserAddress': likedUserAddress, 68 | 'likedUseroccupation': occupation, 69 | 'matched': false, 70 | }); 71 | } 72 | 73 | Future deleteUser(id) async { 74 | await FirebaseFirestore.instance.collection('likeduser').doc(id).delete(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /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 31 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.example.tiki" 47 | minSdkVersion 23 48 | targetSdkVersion 29 49 | versionCode flutterVersionCode.toInteger() 50 | versionName flutterVersionName 51 | multiDexEnabled true 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 | implementation platform('com.google.firebase:firebase-bom:26.8.0') 70 | implementation 'com.google.firebase:firebase-auth-ktx' 71 | implementation 'com.google.firebase:firebase-firestore-ktx' 72 | implementation 'com.google.firebase:firebase-inappmessaging-ktx' 73 | implementation 'com.google.firebase:firebase-dynamic-links-ktx' 74 | implementation 'com.google.firebase:firebase-messaging-ktx' 75 | implementation 'androidx.multidex:multidex:2.0.1' 76 | } 77 | apply plugin: 'com.google.gms.google-services' 78 | -------------------------------------------------------------------------------- /lib/pages/onboarding/onboarding_pictures.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:google_fonts/google_fonts.dart'; 3 | 4 | import 'package:step_progress_indicator/step_progress_indicator.dart'; 5 | import 'package:tiki/widgets/custombtn.dart'; 6 | import 'package:tiki/widgets/header.dart'; 7 | import 'package:tiki/widgets/image_container.dart'; 8 | 9 | class Pictures extends StatelessWidget { 10 | final TabController tabController; 11 | 12 | const Pictures({ 13 | Key? key, 14 | required this.tabController, 15 | }) : super(key: key); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Padding( 20 | padding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 50), 21 | child: Column( 22 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 23 | mainAxisSize: MainAxisSize.max, 24 | children: [ 25 | Column( 26 | crossAxisAlignment: CrossAxisAlignment.start, 27 | children: [ 28 | Column( 29 | crossAxisAlignment: CrossAxisAlignment.center, 30 | mainAxisAlignment: MainAxisAlignment.center, 31 | children: [ 32 | Text('STEP 3 OF 6', 33 | textAlign: TextAlign.center, 34 | style: GoogleFonts.roboto( 35 | fontSize: 15, 36 | color: Theme.of(context).primaryColor, 37 | fontWeight: FontWeight.w500)), 38 | const SizedBox(height: 7), 39 | ], 40 | ), 41 | const CustomTextHeader( 42 | text: 'Add 2 or More Pictures Of Yourself'), 43 | const SizedBox(height: 20), 44 | Row( 45 | children: const [ 46 | CustomImageContainer(), 47 | CustomImageContainer(), 48 | CustomImageContainer(), 49 | ], 50 | ), 51 | Row( 52 | children: const [ 53 | CustomImageContainer(), 54 | CustomImageContainer(), 55 | CustomImageContainer(), 56 | ], 57 | ), 58 | ], 59 | ), 60 | Column( 61 | children: [ 62 | StepProgressIndicator( 63 | totalSteps: 6, 64 | currentStep: 4, 65 | selectedColor: Theme.of(context).primaryColor, 66 | unselectedColor: Theme.of(context).backgroundColor, 67 | ), 68 | SizedBox(height: 10), 69 | CustomButton(tabController: tabController, text: 'NEXT STEP'), 70 | ], 71 | ), 72 | ], 73 | ), 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/pages/onboarding/onboarding_location.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:google_fonts/google_fonts.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | import 'package:step_progress_indicator/step_progress_indicator.dart'; 7 | import 'package:tiki/authentications_bloc/cubits/signup_cubit.dart'; 8 | import 'package:tiki/widgets/custom_textfield.dart'; 9 | import 'package:tiki/widgets/custombtn.dart'; 10 | import 'package:tiki/widgets/header.dart'; 11 | 12 | class Location extends StatelessWidget { 13 | final TabController tabController; 14 | 15 | const Location({ 16 | Key? key, 17 | required this.tabController, 18 | }) : super(key: key); 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return BlocBuilder( 23 | builder: (context, state) { 24 | return Padding( 25 | padding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 50), 26 | child: Column( 27 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 28 | mainAxisSize: MainAxisSize.max, 29 | children: [ 30 | Column( 31 | crossAxisAlignment: CrossAxisAlignment.start, 32 | children: [ 33 | Text('STEP 5 OF 5', 34 | textAlign: TextAlign.center, 35 | style: GoogleFonts.roboto( 36 | fontSize: 15, 37 | color: Theme.of(context).primaryColor, 38 | fontWeight: FontWeight.w500)), 39 | const SizedBox(height: 7), 40 | const CustomTextHeader(text: 'Where Are You?'), 41 | const SizedBox(height: 10), 42 | CustomTextField( 43 | icon: Icons.location_on, 44 | hint: 'E.g Nairobi, Kenya', 45 | onChanged: (value) { 46 | context.read().locatioChanged(value); 47 | print(state.age); 48 | }, 49 | // controller: controller, 50 | ), 51 | ], 52 | ), 53 | Column( 54 | children: [ 55 | StepProgressIndicator( 56 | totalSteps: 6, 57 | currentStep: 6, 58 | selectedColor: Theme.of(context).primaryColor, 59 | unselectedColor: Theme.of(context).backgroundColor, 60 | ), 61 | const SizedBox(height: 10), 62 | CustomButton(tabController: tabController, text: 'DONE'), 63 | ], 64 | ), 65 | ], 66 | ), 67 | ); 68 | }, 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/widgets/custom_text_container.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:google_fonts/google_fonts.dart'; 4 | 5 | class CustomTextContainer extends StatefulWidget { 6 | final String text; 7 | final bool isSelected; 8 | final VoidCallback onPressed; 9 | 10 | const CustomTextContainer( 11 | {Key? key, 12 | required this.text, 13 | required this.onPressed, 14 | this.isSelected = false}) 15 | : super(key: key); 16 | 17 | @override 18 | State createState() => _CustomTextContainerState(); 19 | } 20 | 21 | class _CustomTextContainerState extends State { 22 | @override 23 | Widget build(BuildContext context) { 24 | return GestureDetector( 25 | onTap: widget.onPressed, 26 | child: Padding( 27 | padding: const EdgeInsets.only( 28 | top: 10.0, 29 | right: 5, 30 | ), 31 | child: Stack( 32 | children: [ 33 | Container( 34 | height: 95, 35 | width: MediaQuery.of(context).size.width / 1 - 10, 36 | padding: const EdgeInsets.symmetric( 37 | horizontal: 10, 38 | ), 39 | decoration: BoxDecoration( 40 | borderRadius: BorderRadius.circular(25), 41 | color: Colors.white, 42 | boxShadow: [ 43 | BoxShadow( 44 | color: Colors.black.withOpacity(0.1), 45 | offset: Offset(0, 3), 46 | blurRadius: 10, 47 | ), 48 | BoxShadow( 49 | color: Colors.black.withOpacity(0.1), 50 | offset: Offset(0, 3), 51 | blurRadius: 10, 52 | ) 53 | ], 54 | ), 55 | child: Center( 56 | child: FittedBox( 57 | fit: BoxFit.scaleDown, 58 | child: Text(widget.text, 59 | softWrap: false, 60 | overflow: TextOverflow.ellipsis, 61 | style: GoogleFonts.aBeeZee( 62 | fontSize: 15, 63 | color: Colors.black, 64 | )), 65 | ), 66 | ), 67 | ), 68 | Visibility( 69 | visible: widget.isSelected, 70 | child: Positioned( 71 | bottom: 3, 72 | right: 10, 73 | child: Icon( 74 | Icons.verified, 75 | color: Theme.of(context).colorScheme.secondary, 76 | size: 15, 77 | )), 78 | ) 79 | ], 80 | ), 81 | ), 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/authentications_bloc/cubits/signup_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:cloud_firestore/cloud_firestore.dart'; 3 | 4 | import 'package:equatable/equatable.dart'; 5 | import 'package:tiki/respositories/mainauth.dart'; 6 | 7 | part 'signup_state.dart'; 8 | 9 | class SignupCubit extends Cubit { 10 | final AuthRepository _authRepository; 11 | 12 | SignupCubit({required AuthRepository authRepository}) 13 | : _authRepository = authRepository, 14 | super(SignupState.initial()); 15 | 16 | void emailChanged(String value) { 17 | emit(state.copyWith(email: value, status: SignupStatus.initial)); 18 | } 19 | 20 | void passwordChanged(String value) { 21 | emit(state.copyWith(password: value, status: SignupStatus.initial)); 22 | } 23 | 24 | void ageChanged(String value) { 25 | emit(state.copyWith(age: value, status: SignupStatus.initial)); 26 | } 27 | 28 | void usernamechanged(String value) { 29 | emit(state.copyWith(username: value, status: SignupStatus.initial)); 30 | } 31 | 32 | void genderChanged(String value) { 33 | emit(state.copyWith(gender: value, status: SignupStatus.initial)); 34 | } 35 | 36 | void biochange(String value) { 37 | emit(state.copyWith(bio: value, status: SignupStatus.initial)); 38 | } 39 | 40 | void interestSelected(List value) { 41 | emit(state.copyWith(interest: value, status: SignupStatus.initial)); 42 | } 43 | 44 | void locatioChanged(String location) { 45 | emit(state.copyWith(location: location, status: SignupStatus.initial)); 46 | } 47 | 48 | void signUpWithCredentials() async { 49 | if (!state.isFormValid || state.status == SignupStatus.submitting) return; 50 | emit( 51 | state.copyWith(status: SignupStatus.submitting), 52 | ); 53 | try { 54 | await _authRepository 55 | .signUp(email: state.email, password: state.password) 56 | .then((value) { 57 | _authRepository.saveUser( 58 | email: state.email, 59 | password: state.password, 60 | username: state.username, 61 | ); 62 | }); 63 | emit( 64 | state.copyWith(status: SignupStatus.success), 65 | ); 66 | } catch (_) {} 67 | } 68 | 69 | void updateDatabase() async { 70 | try { 71 | await _authRepository.updateUser( 72 | age: state.age, 73 | gender: state.gender, 74 | ); 75 | } catch (_) {} 76 | } 77 | 78 | void updateBio() async { 79 | try { 80 | await _authRepository.updateBio( 81 | bio: state.bio, 82 | interest: state.interest, 83 | ); 84 | } catch (e) {} 85 | } 86 | 87 | void updateLocation() async { 88 | try { 89 | await _authRepository.updateLocation( 90 | location: state.location, 91 | geoPoint: const GeoPoint(0.0, 0.0), 92 | ); 93 | } catch (e) {} 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /lib/respositories/bloc/searchbloc.dart: -------------------------------------------------------------------------------- 1 | // import 'dart:async'; 2 | // import 'package:bloc/bloc.dart'; 3 | 4 | // import 'package:meta/meta.dart'; 5 | // import 'package:tiki/models/user.dart'; 6 | // import 'package:tiki/respositories/bloc/search_event.dart'; 7 | // import 'package:tiki/respositories/bloc/serachstate.dart'; 8 | // import 'package:tiki/respositories/searchrepository.dart'; 9 | // import 'package:tiki/respositories/usersrepo.dart'; 10 | 11 | // class SearchBloc extends Bloc { 12 | // SearchRepository _searchRepository; 13 | 14 | // SearchBloc({required SearchRepository searchRepository}) 15 | // : assert(searchRepository != null), 16 | // _searchRepository = searchRepository, 17 | // super(InitialSearchState()); 18 | 19 | // @override 20 | // SearchState get initialState => InitialSearchState(); 21 | 22 | // @override 23 | // Stream mapEventToState( 24 | // SearchEvent event, 25 | // ) async* { 26 | // if (event is SelectUserEvent) { 27 | // yield* _mapSelectToState( 28 | // currentUserId: event.currentUserId, 29 | // selectedUserId: event.selectedUserId, 30 | // name: event.name, 31 | // photoUrl: event.photoUrl); 32 | // } 33 | // if (event is PassUserEvent) { 34 | // yield* _mapPassToState( 35 | // currentUserId: event.currentUserId, 36 | // selectedUserId: event.selectedUserId, 37 | // ); 38 | // } 39 | // if (event is LoadUserEvent) { 40 | // yield* _mapLoadUserToState(currentUserId: event.userId); 41 | // } 42 | // } 43 | 44 | // Stream _mapSelectToState( 45 | // {required String currentUserId, 46 | // required String selectedUserId, 47 | // required String name, 48 | // required String photoUrl}) async* { 49 | // yield LoadingState(); 50 | 51 | // User user = await _searchRepository.chooseUser( 52 | // currentUserId, selectedUserId, name, photoUrl); 53 | 54 | // User currentUser = await _searchRepository.getUserInterests(currentUserId); 55 | // yield LoadUserState(user, currentUser); 56 | // } 57 | 58 | // Stream _mapPassToState( 59 | // {required String currentUserId, required String selectedUserId}) async* { 60 | // yield LoadingState(); 61 | // User user = await _searchRepository.passUser(currentUserId, selectedUserId); 62 | // User currentUser = await _searchRepository.getUserInterests(currentUserId); 63 | 64 | // yield LoadUserState(user, currentUser); 65 | // } 66 | 67 | // Stream _mapLoadUserToState( 68 | // {required String currentUserId}) async* { 69 | // yield LoadingState(); 70 | // User user = await _searchRepository.getUser(currentUserId); 71 | // User currentUser = await _searchRepository.getUserInterests(currentUserId); 72 | 73 | // yield LoadUserState(user, currentUser); 74 | // } 75 | // } 76 | -------------------------------------------------------------------------------- /lib/pages/onboarding/onboarding_first.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:google_fonts/google_fonts.dart'; 3 | import 'package:lottie/lottie.dart'; 4 | import 'package:tiki/widgets/custombtn.dart'; 5 | 6 | import '../signin.dart'; 7 | 8 | class Start extends StatefulWidget { 9 | final TabController tabController; 10 | 11 | const Start({ 12 | Key? key, 13 | required this.tabController, 14 | }) : super(key: key); 15 | 16 | @override 17 | State createState() => _StartState(); 18 | } 19 | 20 | class _StartState extends State { 21 | @override 22 | Widget build(BuildContext context) { 23 | return Padding( 24 | padding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 50), 25 | child: Column( 26 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 27 | children: [ 28 | Column( 29 | children: [ 30 | SizedBox( 31 | height: 200, 32 | width: 200, 33 | child: Lottie.asset( 34 | 'assets/animations/onboaring_love.json', 35 | ), 36 | ), 37 | const SizedBox(height: 50), 38 | Text('Welcome to DISCOVER'.toUpperCase(), 39 | style: GoogleFonts.aBeeZee( 40 | fontSize: 21, 41 | fontWeight: FontWeight.bold, 42 | )), 43 | const SizedBox(height: 20), 44 | Text( 45 | 'Discover is a platform that helps you find new friends and connect with people who share your interests and passions with you.', 46 | style: GoogleFonts.aBeeZee( 47 | fontSize: 15, 48 | ), 49 | textAlign: TextAlign.center, 50 | ), 51 | ], 52 | ), 53 | Column( 54 | children: [ 55 | GestureDetector( 56 | onTap: () { 57 | Navigator.push( 58 | context, 59 | MaterialPageRoute( 60 | builder: (context) => const SigninPage())); 61 | }, 62 | child: RichText( 63 | text: TextSpan(children: [ 64 | TextSpan( 65 | text: 'Already have an account? ', 66 | style: GoogleFonts.aBeeZee( 67 | fontSize: 15, 68 | color: Colors.black, 69 | ), 70 | ), 71 | TextSpan( 72 | text: 'Sign in', 73 | style: GoogleFonts.aBeeZee( 74 | color: Theme.of(context).primaryColor, 75 | fontSize: 15, 76 | ), 77 | ), 78 | ])), 79 | ), 80 | const SizedBox(height: 10), 81 | CustomButton( 82 | tabController: widget.tabController, text: 'GET STARTED'), 83 | ], 84 | ), 85 | ], 86 | ), 87 | ); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /lib/widgets/image_container.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:image_picker/image_picker.dart'; 3 | import 'package:tiki/respositories/storage_repository.dart'; 4 | 5 | import '../authentications_bloc/cubits/signup_cubit.dart'; 6 | 7 | class CustomImageContainer extends StatefulWidget { 8 | final String? imageUrl; 9 | const CustomImageContainer({ 10 | Key? key, 11 | this.imageUrl, 12 | }) : super(key: key); 13 | 14 | @override 15 | State createState() => _CustomImageContainerState(); 16 | } 17 | 18 | class _CustomImageContainerState extends State { 19 | @override 20 | Widget build(BuildContext context) { 21 | XFile? file; 22 | return Padding( 23 | padding: const EdgeInsets.only(bottom: 10.0, right: 10.0), 24 | child: Container( 25 | height: 150, 26 | width: 100, 27 | decoration: BoxDecoration( 28 | borderRadius: BorderRadius.circular(5.0), 29 | border: Border( 30 | bottom: BorderSide( 31 | width: 1, 32 | color: widget.imageUrl != null 33 | ? Colors.white 34 | : Theme.of(context).primaryColor, 35 | ), 36 | top: BorderSide( 37 | width: 1, 38 | color: widget.imageUrl != null 39 | ? Colors.white 40 | : Theme.of(context).primaryColor, 41 | ), 42 | left: BorderSide( 43 | width: 1, 44 | color: widget.imageUrl != null 45 | ? Colors.white 46 | : Theme.of(context).primaryColor, 47 | ), 48 | right: BorderSide( 49 | width: 1, 50 | color: widget.imageUrl != null 51 | ? Colors.white 52 | : Theme.of(context).primaryColor, 53 | ), 54 | ), 55 | ), 56 | child: (widget.imageUrl == null) 57 | ? Align( 58 | alignment: Alignment.bottomRight, 59 | child: IconButton( 60 | icon: Icon( 61 | Icons.add_circle, 62 | color: Theme.of(context).accentColor, 63 | ), 64 | onPressed: () async { 65 | ImagePicker _picker = ImagePicker(); 66 | final XFile? image = 67 | await _picker.pickImage(source: ImageSource.gallery); 68 | setState(() { 69 | file = image; 70 | }); 71 | 72 | if (image == null) { 73 | ScaffoldMessenger.of(context).showSnackBar( 74 | const SnackBar(content: Text("No image selected"))); 75 | } else { 76 | StorageRepository().uploadImage(image); 77 | } 78 | }, 79 | ), 80 | ) 81 | : Image.network( 82 | widget.imageUrl ?? "", 83 | fit: BoxFit.cover, 84 | ), 85 | ), 86 | ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /assets/svgs/likes_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /lib/models/messages.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:intl/intl.dart'; 3 | 4 | class Message extends Equatable { 5 | final int id; 6 | final int senderId; 7 | final int receiverId; 8 | final String message; 9 | final DateTime dateTime; 10 | final DateTime timeString; 11 | 12 | const Message({ 13 | required this.id, 14 | required this.senderId, 15 | required this.receiverId, 16 | required this.message, 17 | required this.dateTime, 18 | required this.timeString, 19 | }); 20 | 21 | @override 22 | List get props => [ 23 | id, 24 | senderId, 25 | receiverId, 26 | message, 27 | dateTime, 28 | timeString, 29 | ]; 30 | 31 | static List messages = [ 32 | Message( 33 | id: 1, 34 | senderId: 1, 35 | receiverId: 2, 36 | message: 'Hey, how are you?', 37 | dateTime: DateTime.now(), 38 | timeString: DateTime(2020, 1, 1, 1, 1, 1)), 39 | Message( 40 | id: 2, 41 | senderId: 2, 42 | receiverId: 1, 43 | message: 'I\'m good, thank you.', 44 | dateTime: DateTime.now(), 45 | timeString: DateTime(2020, 1, 1, 1, 1, 1)), 46 | Message( 47 | id: 3, 48 | senderId: 1, 49 | receiverId: 2, 50 | message: 'I\'m good, as well. Thank you.', 51 | dateTime: DateTime.now(), 52 | timeString: DateTime(2020, 1, 1, 1, 1, 1)), 53 | Message( 54 | id: 4, 55 | senderId: 1, 56 | receiverId: 3, 57 | message: 'Hey, how are you?', 58 | dateTime: DateTime.now(), 59 | timeString: DateTime(2020, 1, 1, 1, 1, 1)), 60 | Message( 61 | id: 5, 62 | senderId: 3, 63 | receiverId: 1, 64 | message: 'I\'m good, thank you.', 65 | dateTime: DateTime.now(), 66 | timeString: DateTime(2020, 1, 1, 1, 1, 1)), 67 | Message( 68 | id: 6, 69 | senderId: 1, 70 | receiverId: 5, 71 | message: 'Hey, how are you?', 72 | dateTime: DateTime.now(), 73 | timeString: DateTime(2020, 1, 1, 1, 1, 1)), 74 | Message( 75 | id: 7, 76 | senderId: 5, 77 | receiverId: 1, 78 | message: 'I\'m good, thank you.', 79 | dateTime: DateTime.now(), 80 | timeString: DateTime(2020, 1, 1, 1, 1, 1)), 81 | Message( 82 | id: 8, 83 | senderId: 1, 84 | receiverId: 6, 85 | message: 'Hey, how are you?', 86 | dateTime: DateTime.now(), 87 | timeString: DateTime(2020, 1, 1, 1, 1, 1)), 88 | Message( 89 | id: 9, 90 | senderId: 6, 91 | receiverId: 1, 92 | message: 'I\'m good, thank you.', 93 | dateTime: DateTime.now(), 94 | timeString: DateTime(2020, 1, 1, 1, 1, 1)), 95 | Message( 96 | id: 10, 97 | senderId: 1, 98 | receiverId: 7, 99 | message: 'Hey, how are you?', 100 | dateTime: DateTime.now(), 101 | timeString: DateTime(2020, 1, 1, 1, 1, 1)), 102 | Message( 103 | id: 11, 104 | senderId: 7, 105 | receiverId: 1, 106 | message: 'I\'m good, thank you.', 107 | dateTime: DateTime.now(), 108 | timeString: DateTime(2020, 1, 1, 1, 1, 1)), 109 | ]; 110 | } 111 | -------------------------------------------------------------------------------- /lib/respositories/mainauth.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | import 'package:firebase_auth/firebase_auth.dart' as auth; 3 | import 'package:tiki/respositories/auth_repositoties.dart'; 4 | 5 | class AuthRepository extends BaseAuthRepository { 6 | final auth.FirebaseAuth _firebaseAuth; 7 | 8 | AuthRepository({auth.FirebaseAuth? firebaseAuth}) 9 | : _firebaseAuth = firebaseAuth ?? auth.FirebaseAuth.instance; 10 | 11 | Future signUp({ 12 | required String email, 13 | required String password, 14 | }) async { 15 | try { 16 | final credential = await _firebaseAuth.createUserWithEmailAndPassword( 17 | email: email, 18 | password: password, 19 | ); 20 | 21 | final user = credential.user; 22 | return user; 23 | } catch (_) {} 24 | return null; 25 | } 26 | 27 | Future singIn({ 28 | required String email, 29 | required String password, 30 | }) async { 31 | try { 32 | final credential = await _firebaseAuth.signInWithEmailAndPassword( 33 | email: email, 34 | password: password, 35 | ); 36 | 37 | final user = credential.user; 38 | return user; 39 | } catch (error) { 40 | print(error); 41 | return null; 42 | } 43 | } 44 | 45 | Future saveUser({ 46 | required String email, 47 | required String password, 48 | required String username, 49 | }) async { 50 | try { 51 | FirebaseFirestore.instance 52 | .collection('users') 53 | .doc(_firebaseAuth.currentUser!.email) 54 | .set({ 55 | 'email': email, 56 | 'password': password, 57 | 'username': username, 58 | }); 59 | } catch (_) {} 60 | return null; 61 | } 62 | 63 | Future updateUser( 64 | {required String age, required String gender, String? imageUrl}) async { 65 | try { 66 | FirebaseFirestore.instance 67 | .collection('users') 68 | .doc(_firebaseAuth.currentUser!.email) 69 | .update({ 70 | 'age': age, 71 | 'gender': gender, 72 | 'imageUrl': FieldValue.arrayUnion([imageUrl]), 73 | }); 74 | } catch (_) {} 75 | } 76 | 77 | Future updateBio({ 78 | required String bio, 79 | required List interest, 80 | }) async { 81 | try { 82 | FirebaseFirestore.instance 83 | .collection('users') 84 | .doc(_firebaseAuth.currentUser!.email) 85 | .update({ 86 | 'bio': bio, 87 | 'interest': interest, 88 | }); 89 | } catch (_) {} 90 | } 91 | 92 | Future updateLocation({ 93 | required String location, 94 | final GeoPoint? geoPoint, 95 | }) async { 96 | try { 97 | FirebaseFirestore.instance 98 | .collection('users') 99 | .doc(_firebaseAuth.currentUser!.email) 100 | .update({ 101 | 'location': location, 102 | 'currentPostion': GeoPoint(geoPoint!.latitude, geoPoint.longitude), 103 | }); 104 | } catch (_) {} 105 | } 106 | 107 | @override 108 | Stream get user => _firebaseAuth.userChanges(); 109 | 110 | @override 111 | Future signInWithEmailAndPassword( 112 | {String? email, String? password}) { 113 | throw UnimplementedError(); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /lib/pages/onboarding/onboardinng.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:google_fonts/google_fonts.dart'; 4 | import 'package:tiki/authentications_bloc/cubits/signup_cubit.dart'; 5 | import 'package:tiki/pages/onboarding/onboarding_bio.dart'; 6 | import 'package:tiki/pages/onboarding/onboarding_email.dart'; 7 | 8 | import 'package:tiki/pages/onboarding/onboarding_first.dart'; 9 | import 'package:tiki/pages/onboarding/onboarding_location.dart'; 10 | import 'package:tiki/pages/onboarding/onboarding_pictures.dart'; 11 | import 'package:tiki/pages/onboarding/onboarding_specifics.dart'; 12 | import 'package:tiki/respositories/mainauth.dart'; 13 | 14 | class OnboardingScreen extends StatelessWidget { 15 | static const String routeName = '/onboarding'; 16 | 17 | const OnboardingScreen({Key? key}) : super(key: key); 18 | 19 | static Route route() { 20 | return MaterialPageRoute( 21 | settings: const RouteSettings(name: routeName), 22 | builder: (context) => BlocProvider( 23 | create: (_) => 24 | SignupCubit(authRepository: context.read()), 25 | child: const OnboardingScreen(), 26 | ), 27 | ); 28 | } 29 | 30 | static const List tabs = [ 31 | Tab(text: 'Start'), 32 | Tab(text: 'Email'), 33 | Tab(text: 'Demographics'), 34 | Tab(text: 'Pictures'), 35 | Tab(text: 'Biography'), 36 | Tab(text: 'Location') 37 | ]; 38 | 39 | @override 40 | Widget build(BuildContext context) { 41 | return DefaultTabController( 42 | length: tabs.length, 43 | child: Builder(builder: (BuildContext context) { 44 | final TabController tabController = DefaultTabController.of(context)!; 45 | tabController.addListener(() { 46 | if (!tabController.indexIsChanging) {} 47 | }); 48 | return Scaffold( 49 | appBar: AppBar( 50 | backgroundColor: Colors.transparent, 51 | elevation: 0, 52 | centerTitle: true, 53 | title: Padding( 54 | padding: const EdgeInsets.only(right: 60.0), 55 | child: Row( 56 | mainAxisAlignment: MainAxisAlignment.center, 57 | crossAxisAlignment: CrossAxisAlignment.center, 58 | children: [ 59 | Image.asset('assets/images/connect.png', 60 | height: 25, 61 | width: 25, 62 | color: Theme.of(context).colorScheme.secondary), 63 | const SizedBox(width: 5), 64 | Text( 65 | 'Discover', 66 | style: GoogleFonts.aBeeZee( 67 | fontSize: 20, 68 | fontWeight: FontWeight.bold, 69 | color: Theme.of(context).colorScheme.secondary, 70 | ), 71 | ) 72 | ], 73 | ), 74 | ), 75 | ), 76 | body: TabBarView( 77 | physics: NeverScrollableScrollPhysics(), 78 | children: [ 79 | Start(tabController: tabController), 80 | Email(tabController: tabController), 81 | Demo(tabController: tabController), 82 | Pictures(tabController: tabController), 83 | Bio(tabController: tabController), 84 | Location(tabController: tabController), 85 | ], 86 | ), 87 | ); 88 | }), 89 | ); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /lib/respositories/usersrepo.dart: -------------------------------------------------------------------------------- 1 | // import 'package:tiki/models/user.dart'; 2 | // import 'package:cloud_firestore/cloud_firestore.dart'; 3 | 4 | // class SearchRepository { 5 | // final FirebaseFirestore _firestore; 6 | 7 | // SearchRepository({FirebaseFirestore? firestore}) 8 | // : _firestore = firestore ?? FirebaseFirestore.instance; 9 | 10 | // Future chooseUser(currentUserId, selectedUserId, name, photoUrl) async { 11 | // await _firestore 12 | // .collection('users') 13 | // .doc(currentUserId) 14 | // .collection('chosenList') 15 | // .doc(selectedUserId) 16 | // .set({}); 17 | 18 | // await _firestore 19 | // .collection('users') 20 | // .doc(selectedUserId) 21 | // .collection('chosenList') 22 | // .doc(currentUserId) 23 | // .set({}); 24 | 25 | // await _firestore 26 | // .collection('users') 27 | // .doc(selectedUserId) 28 | // .collection('selectedList') 29 | // .doc(currentUserId) 30 | // .set({ 31 | // 'name': name, 32 | // 'photoUrl': photoUrl, 33 | // }); 34 | // return getUser(currentUserId); 35 | // } 36 | 37 | // passUser(currentUserId, selectedUserId) async { 38 | // await _firestore 39 | // .collection('users') 40 | // .doc(selectedUserId) 41 | // .collection('chosenList') 42 | // .doc(currentUserId) 43 | // .set({}); 44 | 45 | // await _firestore 46 | // .collection('users') 47 | // .doc(currentUserId) 48 | // .collection('chosenList') 49 | // .doc(selectedUserId) 50 | // .set({}); 51 | // return getUser(currentUserId); 52 | // } 53 | 54 | // Future getUserInterests(userId) async { 55 | // User currentUser = User(); 56 | 57 | // await _firestore.collection('users').doc(userId).get().then((user) { 58 | // currentUser.name = user['name']; 59 | // currentUser.imageUrls = user['photoUrl'][1]; 60 | // currentUser.gender = user['gender']; 61 | // currentUser.interestedIn = user['interestedIn']; 62 | // }); 63 | // return currentUser; 64 | // } 65 | 66 | // Future getChosenList(userId) async { 67 | // List chosenList = []; 68 | // await _firestore 69 | // .collection('users') 70 | // .doc(userId) 71 | // .collection('chosenList') 72 | // .get() 73 | // .then((docs) { 74 | // for (var doc in docs.docs) { 75 | // if (docs.docs != null) { 76 | // chosenList.add(doc.id); 77 | // } 78 | // } 79 | // }); 80 | // return chosenList; 81 | // } 82 | 83 | // Future getUser(userId) async { 84 | // User _user = User(); 85 | // List chosenList = await getChosenList(userId); 86 | // User currentUser = await getUserInterests(userId); 87 | 88 | // await _firestore.collection('users').get().then((users) { 89 | // for (var user in users.docs) { 90 | // if ((!chosenList.contains(user.id)) && (user.id != userId)) 91 | // // (currentUser.interestedIn == user['gender']) && 92 | // // (user['interestedIn'] == currentUser.gender)) 93 | // { 94 | // _user.id = user.id; 95 | // _user.name = user['name']; 96 | // _user.imageUrls = user['photoUrl'][1]; 97 | // _user.age = user['age']; 98 | // _user.location = user['location']; 99 | // _user.gender = user['gender']; 100 | // _user.interestedIn = user['interestedIn']; 101 | // break; 102 | // } 103 | // } 104 | // }); 105 | 106 | // return _user; 107 | // } 108 | // } 109 | -------------------------------------------------------------------------------- /lib/respositories/searchrepository.dart: -------------------------------------------------------------------------------- 1 | // import 'package:cloud_firestore/cloud_firestore.dart'; 2 | 3 | // import '../models/user.dart'; 4 | 5 | // class SearchRepository { 6 | // final FirebaseFirestore _firestore; 7 | 8 | // SearchRepository({required FirebaseFirestore firestore}) 9 | // : _firestore = firestore ?? FirebaseFirestore.instance; 10 | 11 | // Future chooseUser(currentUserId, selectedUserId, name, photoUrl) async { 12 | // await _firestore 13 | // .collection('users') 14 | // .doc(currentUserId) 15 | // .collection('chosenList') 16 | // .doc(selectedUserId) 17 | // .set({}); 18 | 19 | // await _firestore 20 | // .collection('users') 21 | // .doc(selectedUserId) 22 | // .collection('chosenList') 23 | // .doc(currentUserId) 24 | // .set({}); 25 | 26 | // await _firestore 27 | // .collection('users') 28 | // .doc(selectedUserId) 29 | // .collection('selectedList') 30 | // .doc(currentUserId) 31 | // .set({ 32 | // 'name': name, 33 | // 'photoUrl': photoUrl, 34 | // }); 35 | // return getUser(currentUserId); 36 | // } 37 | 38 | // passUser(currentUserId, selectedUserId) async { 39 | // await _firestore 40 | // .collection('users') 41 | // .doc(selectedUserId) 42 | // .collection('chosenList') 43 | // .doc(currentUserId) 44 | // .set({}); 45 | 46 | // await _firestore 47 | // .collection('users') 48 | // .doc(currentUserId) 49 | // .collection('chosenList') 50 | // .doc(selectedUserId) 51 | // .set({}); 52 | // return getUser(currentUserId); 53 | // } 54 | 55 | // Future getUserInterests(userId) async { 56 | // User currentUser = User(); 57 | 58 | // await _firestore.collection('users').doc(userId).get().then((user) { 59 | // currentUser.name = user['name']; 60 | // currentUser.imageUrls = user['photoUrl']; 61 | // currentUser.gender = user['gender']; 62 | // currentUser.interestedIn = user['interestedIn']; 63 | // }); 64 | // return currentUser; 65 | // } 66 | 67 | // Future getChosenList(userId) async { 68 | // List chosenList = []; 69 | // await _firestore 70 | // .collection('users') 71 | // .doc(userId) 72 | // .collection('chosenList') 73 | // .get() 74 | // .then((docs) { 75 | // for (var doc in docs.docs) { 76 | // if (docs.docs != null) { 77 | // chosenList.add(doc.id); 78 | // } 79 | // } 80 | // }); 81 | // return chosenList; 82 | // } 83 | 84 | // Future getUser(userId) async { 85 | // User _user = User(); 86 | // List chosenList = await getChosenList(userId); 87 | // User currentUser = await getUserInterests(userId); 88 | 89 | // await _firestore.collection('users').get().then((users) { 90 | // for (var user in users.docs) { 91 | // if ((!chosenList.contains(user.id)) && 92 | // (user.id != userId) && 93 | // (currentUser.interestedIn == user['gender']) && 94 | // (user['interestedIn'] == currentUser.gender)) { 95 | // _user.uid = user.id; 96 | // _user.name = user['name']; 97 | // _user.photo = user['photoUrl']; 98 | // _user.age = user['age']; 99 | // _user.location = user['location']; 100 | // _user.gender = user['gender']; 101 | // _user.interestedIn = user['interestedIn']; 102 | // break; 103 | // } 104 | // } 105 | // }); 106 | 107 | // return _user; 108 | // } 109 | // } 110 | -------------------------------------------------------------------------------- /lib/pages/onboarding/onboarding_email.dart: -------------------------------------------------------------------------------- 1 | import 'package:antdesign_icons/antdesign_icons.dart'; 2 | import 'package:eva_icons_flutter/eva_icons_flutter.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_bloc/flutter_bloc.dart'; 5 | import 'package:google_fonts/google_fonts.dart'; 6 | 7 | import 'package:step_progress_indicator/step_progress_indicator.dart'; 8 | import 'package:tiki/authentications_bloc/cubits/signup_cubit.dart'; 9 | import 'package:tiki/widgets/custombtn.dart'; 10 | import 'package:tiki/widgets/header.dart'; 11 | 12 | import '../../widgets/custom_textfield.dart'; 13 | 14 | class Email extends StatelessWidget { 15 | final TabController tabController; 16 | 17 | const Email({ 18 | Key? key, 19 | required this.tabController, 20 | }) : super(key: key); 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return BlocBuilder( 25 | builder: (context, state) { 26 | return Padding( 27 | padding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 50), 28 | child: Column( 29 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 30 | children: [ 31 | Column( 32 | crossAxisAlignment: CrossAxisAlignment.start, 33 | children: [ 34 | Column( 35 | crossAxisAlignment: CrossAxisAlignment.center, 36 | mainAxisAlignment: MainAxisAlignment.center, 37 | children: [ 38 | Text('STEP 1 OF 6', 39 | textAlign: TextAlign.center, 40 | style: GoogleFonts.roboto( 41 | fontSize: 15, 42 | color: Theme.of(context).primaryColor, 43 | fontWeight: FontWeight.w500)), 44 | ], 45 | ), 46 | const SizedBox(height: 7), 47 | const CustomTextHeader(text: 'Choose a Unique Username'), 48 | const SizedBox(height: 7), 49 | CustomTextField( 50 | hint: 'John Doe', 51 | icon: EvaIcons.person, 52 | onChanged: (value) { 53 | context.read().usernamechanged(value); 54 | print(state.username); 55 | }, 56 | ), 57 | const SizedBox(height: 30), 58 | const CustomTextHeader(text: 'What\'s Your Email Address?'), 59 | const SizedBox(height: 7), 60 | CustomTextField( 61 | hint: 'JohnDoe@gmail.com', 62 | icon: Icons.email, 63 | onChanged: (value) { 64 | context.read().emailChanged(value); 65 | print(state.email); 66 | }, 67 | ), 68 | const SizedBox(height: 30), 69 | const CustomTextHeader(text: 'Choose a Password'), 70 | const SizedBox(height: 7), 71 | CustomTextField( 72 | icon: EvaIcons.lock, 73 | hint: '********', 74 | onChanged: (value) { 75 | context.read().passwordChanged(value); 76 | print(state.password); 77 | }, 78 | ), 79 | ], 80 | ), 81 | Column( 82 | children: [ 83 | StepProgressIndicator( 84 | totalSteps: 6, 85 | currentStep: 1, 86 | selectedColor: Theme.of(context).primaryColor, 87 | unselectedColor: Theme.of(context).backgroundColor, 88 | ), 89 | SizedBox(height: 10), 90 | CustomButton(tabController: tabController, text: 'NEXT STEP'), 91 | ], 92 | ), 93 | ], 94 | ), 95 | ); 96 | }, 97 | ); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | tiki 30 | 31 | 32 | 33 | 36 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: tiki 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | # Dependencies specify other packages that your package needs in order to work. 24 | # To automatically upgrade your package dependencies to the latest versions 25 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 26 | # dependencies can be manually updated by changing the version numbers below to 27 | # the latest version available on pub.dev. To see which dependencies have newer 28 | # versions available, run `flutter pub outdated`. 29 | dependencies: 30 | antdesign_icons: ^0.0.3 31 | cached_network_image: ^3.2.0 32 | cloud_firestore: ^3.1.8 33 | cupertino_icons: ^1.0.4 34 | equatable: ^2.0.3 35 | eva_icons_flutter: ^3.1.0 36 | extended_image: ^6.0.1 37 | firebase_auth: ^3.3.7 38 | firebase_core: ^1.12.0 39 | firebase_storage: ^10.2.7 40 | flutter_bloc: ^7.0.0 41 | flutter_datetime_picker: ^1.3.8 42 | flutter_staggered_animations: ^1.0.0 43 | flutter_staggered_grid_view: ^0.6.1 44 | transparent_image: ^1.0.0 45 | flutter_svg: ^1.0.3 46 | font_awesome_flutter: ^9.2.0 47 | geolocator: ^8.2.0 48 | google_fonts: ^2.3.1 49 | image_picker: ^0.8.4+9 50 | latlng: ^0.1.0 51 | lottie: ^1.2.2 52 | meta: ^1.1.8 53 | provider: ^6.0.2 54 | shared_preferences: ^2.0.13 55 | shimmer: ^2.0.0 56 | step_progress_indicator: ^1.0.2 57 | story_view: ^0.13.2 58 | timeago: ^3.2.2 59 | 60 | dev_dependencies: 61 | flutter_lints: ^1.0.0 62 | flutter_test: 63 | sdk: flutter 64 | 65 | # For information on the generic Dart part of this file, see the 66 | # following page: https://dart.dev/tools/pub/pubspec 67 | # The following section is specific to Flutter. 68 | flutter: 69 | 70 | # The following line ensures that the Material Icons font is 71 | # included with your application, so that you can use the icons in 72 | # the material Icons class. 73 | uses-material-design: true 74 | # To add assets to your application, add an assets section, like this: 75 | assets: 76 | - assets/images/ 77 | - assets/animations/ 78 | - assets/svgs/ 79 | # - images/a_dot_ham.jpeg 80 | # An image asset can refer to one or more resolution-specific "variants", see 81 | # https://flutter.dev/assets-and-images/#resolution-aware. 82 | # For details regarding adding assets from package dependencies, see 83 | # https://flutter.dev/assets-and-images/#from-packages 84 | # To add custom fonts to your application, add a fonts section here, 85 | # in this "flutter" section. Each entry in this list should have a 86 | # "family" key with the font family name, and a "fonts" key with a 87 | # list giving the asset and other descriptors for the font. For 88 | # example: 89 | # fonts: 90 | # - family: Schyler 91 | # fonts: 92 | # - asset: fonts/Schyler-Regular.ttf 93 | # - asset: fonts/Schyler-Italic.ttf 94 | # style: italic 95 | # - family: Trajan Pro 96 | # fonts: 97 | # - asset: fonts/TrajanPro.ttf 98 | # - asset: fonts/TrajanPro_Bold.ttf 99 | # weight: 700 100 | # 101 | # For details regarding fonts from package dependencies, 102 | # see https://flutter.dev/custom-fonts/#from-packages 103 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: prefer_const_constructors 2 | 3 | import 'package:firebase_core/firebase_core.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_bloc/flutter_bloc.dart'; 6 | import 'package:provider/provider.dart'; 7 | import 'package:shared_preferences/shared_preferences.dart'; 8 | import 'package:tiki/authentications_bloc/cubits/signup_cubit.dart'; 9 | import 'package:tiki/constatns/app_router.dart'; 10 | import 'package:tiki/models/user.dart'; 11 | import 'package:tiki/pages/homepage.dart'; 12 | import 'package:firebase_auth/firebase_auth.dart' as auth; 13 | import 'package:tiki/pages/onboarding/onboardinng.dart'; 14 | import 'package:tiki/pages/tabs/mainpage.dart'; 15 | import 'package:tiki/providers/userdata.dart'; 16 | import 'package:tiki/respositories/bloc/image_bloc.dart'; 17 | import 'package:tiki/respositories/bloc/swipebloc_bloc.dart'; 18 | import 'package:tiki/respositories/databerepository.dart'; 19 | import 'package:tiki/respositories/mainauth.dart'; 20 | import 'pages/onboarding/onboardinng.dart'; 21 | import 'respositories/baseusers.dart'; 22 | 23 | void main() async { 24 | WidgetsFlutterBinding.ensureInitialized(); 25 | Provider.debugCheckInvalidValueType = null; 26 | await Firebase.initializeApp(); 27 | runApp(MultiProvider( 28 | providers: [ 29 | Provider(create: (_) => UserData()), 30 | ], 31 | child: const MyApp(), 32 | )); 33 | } 34 | 35 | class MyApp extends StatefulWidget { 36 | const MyApp({Key? key}) : super(key: key); 37 | 38 | @override 39 | State createState() => _MyAppState(); 40 | } 41 | 42 | class _MyAppState extends State { 43 | String? status; 44 | void getLoginStatus() async { 45 | SharedPreferences prefs = await SharedPreferences.getInstance(); 46 | 47 | setState(() { 48 | status = prefs.getString('loggedIn'); 49 | }); 50 | } 51 | 52 | @override 53 | void initState() { 54 | // TODO: implement initState 55 | super.initState(); 56 | getLoginStatus(); 57 | } 58 | 59 | // This widget is the root of your application. 60 | @override 61 | Widget build(BuildContext context) { 62 | return MultiRepositoryProvider( 63 | providers: [RepositoryProvider(create: (_) => AuthRepository())], 64 | child: MultiBlocProvider( 65 | providers: [ 66 | BlocProvider( 67 | create: (_) => 68 | SignupCubit(authRepository: context.read()), 69 | child: const OnboardingScreen(), 70 | ), 71 | BlocProvider( 72 | create: (_) => SwipeBloc( 73 | baseUsersRepo: Usersdata(), 74 | )..add(LoadedSwipe()), 75 | ), 76 | BlocProvider( 77 | create: (_) => ImageBloc(databaseRepository: DatabaseRepository()) 78 | ..add(LoadImage())), 79 | ], 80 | child: MaterialApp( 81 | title: 'Discover', 82 | debugShowCheckedModeBanner: false, 83 | initialRoute: OnboardingScreen.routeName, 84 | onGenerateRoute: AppRouter.onGenerateRoute, 85 | theme: ThemeData( 86 | primarySwatch: Colors.red, 87 | bottomSheetTheme: const BottomSheetThemeData( 88 | backgroundColor: Colors.transparent, 89 | elevation: 0, 90 | ), 91 | accentColor: Colors.red, 92 | primaryColorLight: Colors.red), 93 | home: OnboardingScreen(), 94 | ), 95 | ), 96 | ); 97 | } 98 | } 99 | 100 | Future getcureentUser() async { 101 | final auth.FirebaseAuth _auth = auth.FirebaseAuth.instance; 102 | final auth.User user = _auth.currentUser!; 103 | return user; 104 | } 105 | 106 | class AuthenticationWrapper extends StatelessWidget { 107 | const AuthenticationWrapper({Key? key}) : super(key: key); 108 | 109 | @override 110 | Widget build(BuildContext context) { 111 | return FutureBuilder( 112 | future: getcureentUser(), 113 | builder: (context, snapshot) { 114 | if (snapshot.hasData) { 115 | return MainPage(); 116 | } 117 | return OnboardingScreen(); 118 | }, 119 | ); 120 | } 121 | } 122 | 123 | // class AuthenticationWrapper extends StatefulWidget { 124 | // static const String routeName = '/wrapper'; 125 | // static Route route() { 126 | // return MaterialPageRoute( 127 | // settings: const RouteSettings(name: AuthenticationWrapper.routeName), 128 | // builder: (_) => AuthenticationWrapper(), 129 | // ); 130 | // } 131 | 132 | // @override 133 | // State createState() => _AuthenticationWrapperState(); 134 | // } 135 | 136 | // class _AuthenticationWrapperState extends State { 137 | // @override 138 | // Widget build(BuildContext context) { 139 | // return FutureBuilder( 140 | // future: auth.FirebaseAuth.instance.currentUser! as Future, 141 | // builder: (BuildContext context, AsyncSnapshot snapshot) { 142 | // if (snapshot.hasData) { 143 | // auth.User? user = snapshot.data; // this is your user instance 144 | // /// is because there is user already logged 145 | // return HomePage(); 146 | // } 147 | 148 | // /// other way there is no user logged. 149 | // return OnboardingScreen(); 150 | // }); 151 | // } 152 | // } 153 | -------------------------------------------------------------------------------- /lib/pages/onboarding/onboarding_specifics.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:google_fonts/google_fonts.dart'; 4 | import 'package:step_progress_indicator/step_progress_indicator.dart'; 5 | import 'package:tiki/authentications_bloc/cubits/signup_cubit.dart'; 6 | import 'package:tiki/widgets/custom_textfield.dart'; 7 | import 'package:tiki/widgets/custombtn.dart'; 8 | import 'package:tiki/widgets/header.dart'; 9 | 10 | class Demo extends StatefulWidget { 11 | final TabController tabController; 12 | 13 | const Demo({ 14 | Key? key, 15 | required this.tabController, 16 | }) : super(key: key); 17 | 18 | @override 19 | State createState() => _DemoState(); 20 | } 21 | 22 | class _DemoState extends State { 23 | bool selected = false; 24 | String? currentSelectedValue; 25 | String? currentSelectGender; 26 | List ageRange = ["15-20", "20-25", "25-30", "30-35", "35-40", "40 and above"]; 27 | List gender = ["Male", "Female"]; 28 | @override 29 | Widget build(BuildContext context) { 30 | return BlocBuilder( 31 | builder: (context, state) { 32 | return Padding( 33 | padding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 50), 34 | child: Column( 35 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 36 | mainAxisSize: MainAxisSize.max, 37 | children: [ 38 | Column( 39 | crossAxisAlignment: CrossAxisAlignment.start, 40 | children: [ 41 | Text('STEP 2 OF 6', 42 | textAlign: TextAlign.center, 43 | style: GoogleFonts.roboto( 44 | fontSize: 15, 45 | color: Theme.of(context).primaryColor, 46 | fontWeight: FontWeight.w500)), 47 | const SizedBox(height: 7), 48 | const CustomTextHeader(text: 'What\'s Your Gender?'), 49 | const SizedBox(height: 20), 50 | FormField(builder: (FormFieldState state) { 51 | return InputDecorator( 52 | expands: false, 53 | decoration: InputDecoration( 54 | filled: true, 55 | fillColor: Colors.grey.withAlpha(60), 56 | labelStyle: GoogleFonts.poppins(color: Colors.black), 57 | errorStyle: const TextStyle( 58 | color: Colors.redAccent, fontSize: 16.0), 59 | hintStyle: GoogleFonts.poppins(color: Colors.black), 60 | border: InputBorder.none), 61 | isEmpty: currentSelectedValue == '', 62 | child: DropdownButtonHideUnderline( 63 | child: DropdownButton( 64 | hint: Text( 65 | 'Select your Gender', 66 | style: GoogleFonts.aBeeZee( 67 | fontSize: 12, 68 | ), 69 | ), 70 | value: currentSelectedValue, 71 | isDense: true, 72 | onChanged: (String? newValue) { 73 | setState(() { 74 | currentSelectedValue = newValue; 75 | state.didChange(newValue); 76 | selected = true; 77 | context 78 | .read() 79 | .genderChanged(newValue!); 80 | }); 81 | }, 82 | items: gender.map((dynamic value) { 83 | return DropdownMenuItem( 84 | value: value, 85 | child: Text( 86 | value, 87 | style: GoogleFonts.poppins( 88 | fontSize: 12, 89 | ), 90 | ), 91 | ); 92 | }).toList(), 93 | ), 94 | ), 95 | ); 96 | }), 97 | const SizedBox(height: 100), 98 | const CustomTextHeader(text: 'What\'s Your Age?'), 99 | CustomTextField( 100 | icon: Icons.percent, 101 | hint: 'ENTER YOUR AGE', 102 | onChanged: (value) { 103 | context.read().ageChanged(value); 104 | print(state.age); 105 | }, 106 | // controller: controller, 107 | ), 108 | ], 109 | ), 110 | Column( 111 | children: [ 112 | StepProgressIndicator( 113 | totalSteps: 6, 114 | currentStep: 3, 115 | selectedColor: Theme.of(context).primaryColor, 116 | unselectedColor: Theme.of(context).backgroundColor, 117 | ), 118 | const SizedBox(height: 10), 119 | CustomButton( 120 | tabController: widget.tabController, text: 'NEXT STEP'), 121 | ], 122 | ), 123 | ], 124 | ), 125 | ); 126 | }, 127 | ); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /lib/pages/onboarding/onboarding_bio.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:google_fonts/google_fonts.dart'; 4 | import 'package:step_progress_indicator/step_progress_indicator.dart'; 5 | import 'package:tiki/authentications_bloc/cubits/signup_cubit.dart'; 6 | import 'package:tiki/widgets/custom_text_container.dart'; 7 | import 'package:tiki/widgets/custom_textfield.dart'; 8 | import 'package:tiki/widgets/custombtn.dart'; 9 | import 'package:tiki/widgets/header.dart'; 10 | 11 | class Bio extends StatefulWidget { 12 | final TabController tabController; 13 | 14 | const Bio({ 15 | Key? key, 16 | required this.tabController, 17 | }) : super(key: key); 18 | 19 | @override 20 | State createState() => _BioState(); 21 | } 22 | 23 | class _BioState extends State { 24 | bool isSelect = false; 25 | final int isSelected = 0; 26 | final List seletctedInterest = []; 27 | final List interests = const [ 28 | 'Coding', 29 | 'Design', 30 | 'Music', 31 | 'Dancing', 32 | 'Reading', 33 | 'Cooking', 34 | 'Traveling', 35 | 'Photography', 36 | 'Fashion', 37 | 'Art', 38 | 'Sports', 39 | 'Gaming', 40 | 'Fitness', 41 | 'Nature', 42 | 'Technology', 43 | 'Writing', 44 | 'Hiking', 45 | ]; 46 | @override 47 | Widget build(BuildContext context) { 48 | final controller = TextEditingController(); 49 | return SingleChildScrollView( 50 | child: BlocBuilder( 51 | builder: (context, state) { 52 | return Padding( 53 | padding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 50), 54 | child: Column( 55 | crossAxisAlignment: CrossAxisAlignment.start, 56 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 57 | mainAxisSize: MainAxisSize.max, 58 | children: [ 59 | Text('STEP 4 OF 5', 60 | textAlign: TextAlign.center, 61 | style: GoogleFonts.roboto( 62 | fontSize: 15, 63 | color: Theme.of(context).primaryColor, 64 | fontWeight: FontWeight.w500)), 65 | const SizedBox(height: 7), 66 | Column( 67 | crossAxisAlignment: CrossAxisAlignment.start, 68 | children: [ 69 | const CustomTextHeader(text: 'Describe Yourself'), 70 | const SizedBox(height: 10), 71 | CustomTextField( 72 | icon: Icons.person_add, 73 | hint: 'Software Engineer at Google', 74 | onChanged: (value) { 75 | context.read().biochange(value); 76 | print(state.bio); 77 | }, 78 | // controller: controller, 79 | ), 80 | const SizedBox(height: 100), 81 | Row( 82 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 83 | children: [ 84 | const CustomTextHeader( 85 | text: 'Selet 3 or more interests'), 86 | Text( 87 | '${seletctedInterest.length}/${interests.length}', 88 | ) 89 | ], 90 | ), 91 | SizedBox( 92 | height: MediaQuery.of(context).size.height / 2.2, 93 | width: double.infinity, 94 | child: AnimatedContainer( 95 | duration: const Duration(milliseconds: 500), 96 | child: GridView.count( 97 | shrinkWrap: true, 98 | childAspectRatio: 21 / 11, 99 | mainAxisSpacing: 10, 100 | crossAxisCount: 3, 101 | children: interests.map((interest) { 102 | return Padding( 103 | padding: const EdgeInsets.all(4.0), 104 | child: CustomTextContainer( 105 | isSelected: 106 | seletctedInterest.contains(interest) 107 | ? true 108 | : false, 109 | onPressed: () { 110 | setState( 111 | () { 112 | if (seletctedInterest 113 | .contains(interest)) { 114 | seletctedInterest.remove(interest); 115 | } else { 116 | seletctedInterest.add(interest); 117 | context 118 | .read() 119 | .interestSelected( 120 | seletctedInterest); 121 | } 122 | }, 123 | ); 124 | print(state.interest); 125 | }, 126 | text: interest), 127 | ); 128 | }).toList(), 129 | ), 130 | ), 131 | ) 132 | ], 133 | ), 134 | Column( 135 | children: [ 136 | StepProgressIndicator( 137 | totalSteps: 6, 138 | currentStep: 5, 139 | selectedColor: Theme.of(context).primaryColor, 140 | unselectedColor: Theme.of(context).backgroundColor, 141 | ), 142 | const SizedBox(height: 10), 143 | CustomButton( 144 | tabController: widget.tabController, text: 'NEXT STEP'), 145 | ], 146 | ), 147 | ], 148 | ), 149 | ); 150 | }, 151 | ), 152 | ); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /lib/widgets/likes.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | import 'package:firebase_auth/firebase_auth.dart'; 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:google_fonts/google_fonts.dart'; 6 | import 'package:tiki/pages/tabs/likedDetailsPage.dart'; 7 | 8 | class Likes extends StatelessWidget { 9 | const Likes({ 10 | Key? key, 11 | }) : super(key: key); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Column( 16 | children: [ 17 | const SizedBox(height: 20), 18 | Text( 19 | 'Upgrade to Premium to see the full list of everyone that liked you.', 20 | textAlign: TextAlign.center, 21 | style: GoogleFonts.aBeeZee( 22 | fontSize: 16, 23 | color: Colors.black54, 24 | ), 25 | ), 26 | const SizedBox(height: 30), 27 | Expanded( 28 | child: FutureBuilder( 29 | future: FirebaseFirestore.instance 30 | .collection('likeduser') 31 | .where('likedUserEmail', 32 | isEqualTo: FirebaseAuth.instance.currentUser!.email) 33 | .where('matched', isEqualTo: false) 34 | .get(), 35 | builder: (context, AsyncSnapshot snapshot) { 36 | if (snapshot.connectionState == ConnectionState.waiting) { 37 | return Center( 38 | child: CircularProgressIndicator( 39 | valueColor: AlwaysStoppedAnimation( 40 | Theme.of(context).primaryColor), 41 | ), 42 | ); 43 | } 44 | if (snapshot.data!.docs.isEmpty) { 45 | return Center( 46 | child: Text( 47 | 'No one liked you recently', 48 | style: GoogleFonts.aBeeZee( 49 | fontSize: 16, 50 | color: Colors.black54, 51 | ), 52 | )); 53 | } 54 | return GridView.builder( 55 | itemCount: snapshot.data!.docs.length, 56 | addAutomaticKeepAlives: true, 57 | physics: const BouncingScrollPhysics(), 58 | gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( 59 | crossAxisCount: 2, 60 | childAspectRatio: 7 / 10, 61 | ), 62 | itemBuilder: (context, index) { 63 | return Padding( 64 | padding: const EdgeInsets.all(8.0), 65 | child: GestureDetector( 66 | onTap: () { 67 | Navigator.push( 68 | context, 69 | CupertinoPageRoute( 70 | builder: (context) => LikedDetailsPage( 71 | matched: snapshot.data!.docs[index] 72 | ['matched'], 73 | docid: snapshot.data!.docs[index].id, 74 | liedUserImageUrls: snapshot 75 | .data!.docs[index]['imageUrl'], 76 | likedJob: snapshot.data!.docs[index] 77 | ['address'], 78 | likedUserName: snapshot 79 | .data!.docs[index]['username'], 80 | likedUserage: snapshot.data!.docs[index] 81 | ['age'], 82 | likedUserinterests: snapshot 83 | .data!.docs[index]['interest'], 84 | ))); 85 | }, 86 | child: Container( 87 | height: 180, 88 | width: 100, 89 | child: Align( 90 | alignment: Alignment.bottomLeft, 91 | child: Padding( 92 | padding: const EdgeInsets.all(8.0), 93 | child: Column( 94 | crossAxisAlignment: 95 | CrossAxisAlignment.start, 96 | mainAxisAlignment: MainAxisAlignment.end, 97 | children: [ 98 | Row( 99 | children: [ 100 | Text( 101 | snapshot.data!.docs[index] 102 | ['username'], 103 | style: GoogleFonts.aBeeZee( 104 | fontSize: 17, 105 | fontWeight: FontWeight.w700, 106 | color: Colors.white, 107 | ), 108 | ), 109 | const SizedBox(width: 5), 110 | Text( 111 | snapshot.data!.docs[index]['age'], 112 | style: GoogleFonts.aBeeZee( 113 | fontSize: 15, 114 | fontWeight: FontWeight.w600, 115 | color: Colors.white, 116 | ), 117 | ), 118 | ], 119 | ), 120 | Text( 121 | 'Expires in: ' '1 day', 122 | style: GoogleFonts.aBeeZee( 123 | fontSize: 11, 124 | fontWeight: FontWeight.w500, 125 | color: Colors.white, 126 | ), 127 | ), 128 | ], 129 | ), 130 | )), 131 | decoration: BoxDecoration( 132 | image: DecorationImage( 133 | fit: BoxFit.cover, 134 | image: NetworkImage(snapshot.data!.docs[index] 135 | ['imageUrl'][1])), 136 | borderRadius: BorderRadius.circular(3), 137 | )), 138 | ), 139 | ); 140 | }, 141 | ); 142 | }), 143 | ), 144 | ], 145 | ); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /lib/pages/tabs/mainpage.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:cloud_firestore/cloud_firestore.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:google_fonts/google_fonts.dart'; 5 | import 'package:provider/provider.dart'; 6 | import 'package:shimmer/shimmer.dart'; 7 | import 'package:tiki/models/chat.dart'; 8 | import 'package:tiki/pages/homepage.dart'; 9 | import 'package:flutter/cupertino.dart'; 10 | import 'package:tiki/pages/tabs/categoryscreen.dart'; 11 | import 'package:tiki/pages/tabs/chatpage.dart'; 12 | import 'package:tiki/pages/tabs/likes_page.dart'; 13 | import 'package:tiki/profile.dart'; 14 | import 'package:tiki/providers/userdata.dart'; 15 | 16 | class MainPage extends StatefulWidget { 17 | const MainPage({Key? key}) : super(key: key); 18 | 19 | @override 20 | _MainPageState createState() => _MainPageState(); 21 | } 22 | 23 | class _MainPageState extends State { 24 | int _selectedIndex = 0; 25 | final PageController _pageController = PageController(); 26 | @override 27 | Widget build(BuildContext context) { 28 | var userData = Provider.of(context); 29 | List page = [ 30 | HomePage(), 31 | Container(), 32 | const MatchesScreen(), 33 | ]; 34 | return Scaffold( 35 | appBar: AppBar( 36 | leadingWidth: 100, 37 | leading: Padding( 38 | padding: const EdgeInsets.only(top: 4.0), 39 | child: GestureDetector( 40 | onTap: () { 41 | Navigator.push( 42 | context, 43 | CupertinoPageRoute( 44 | builder: (context) => const DrawerWidget())); 45 | }, 46 | child: FutureBuilder( 47 | future: userData.getData(), 48 | builder: (context, AsyncSnapshot snapshot) { 49 | if (snapshot.connectionState == ConnectionState.waiting) { 50 | return Shimmer.fromColors( 51 | baseColor: Colors.grey, 52 | highlightColor: Colors.white, 53 | child: Container( 54 | height: 40, 55 | width: 40, 56 | decoration: const BoxDecoration( 57 | shape: BoxShape.circle, 58 | color: Colors.white, 59 | )), 60 | ); 61 | } 62 | // saveUser(snapshot.data!['imageUrl'][1]); 63 | return Container( 64 | height: 40, 65 | width: 40, 66 | decoration: BoxDecoration( 67 | shape: BoxShape.circle, 68 | color: Colors.white, 69 | image: DecorationImage( 70 | fit: BoxFit.cover, 71 | image: CachedNetworkImageProvider( 72 | snapshot.data!['imageUrl'][1] ?? ''), 73 | ), 74 | )); 75 | }), 76 | ), 77 | ), 78 | actions: [ 79 | Padding( 80 | padding: const EdgeInsets.only(right: 8.0), 81 | child: IconButton( 82 | icon: Image.asset( 83 | 'assets/images/bell.png', 84 | height: 25, 85 | width: 25, 86 | color: Colors.grey, 87 | ), 88 | onPressed: () {}), 89 | ), 90 | ], 91 | centerTitle: true, 92 | backgroundColor: Colors.transparent, 93 | elevation: 0, 94 | title: Padding( 95 | padding: const EdgeInsets.only(right: 20.0), 96 | child: Row( 97 | mainAxisAlignment: MainAxisAlignment.center, 98 | crossAxisAlignment: CrossAxisAlignment.center, 99 | children: [ 100 | Image.asset('assets/images/connect.png', 101 | height: 25, 102 | width: 25, 103 | color: Theme.of(context).colorScheme.secondary), 104 | const SizedBox(width: 5), 105 | Text( 106 | 'Discover', 107 | style: GoogleFonts.aBeeZee( 108 | fontSize: 20, 109 | fontWeight: FontWeight.bold, 110 | color: Theme.of(context).colorScheme.secondary, 111 | ), 112 | ) 113 | ], 114 | ), 115 | ), 116 | ), 117 | body: PageView( 118 | onPageChanged: (page) { 119 | setState(() { 120 | _selectedIndex = page; 121 | }); 122 | }, 123 | controller: _pageController, 124 | children: const [ 125 | HomePage(), 126 | ListPage(), 127 | Category(), 128 | MatchesScreen(), 129 | ], 130 | ), 131 | bottomNavigationBar: Container( 132 | decoration: BoxDecoration( 133 | boxShadow: [ 134 | BoxShadow( 135 | color: Colors.grey.withAlpha(50), 136 | blurRadius: 5, 137 | ), 138 | ], 139 | ), 140 | child: BottomNavigationBar( 141 | currentIndex: _selectedIndex, 142 | type: BottomNavigationBarType.fixed, 143 | onTap: _onTappedBar, 144 | showSelectedLabels: false, 145 | showUnselectedLabels: false, 146 | elevation: 5, 147 | items: [ 148 | BottomNavigationBarItem( 149 | icon: Image.asset( 150 | 'assets/images/connect.png', 151 | height: 25, 152 | width: 25, 153 | color: _selectedIndex == 0 154 | ? Theme.of(context).colorScheme.secondary 155 | : Colors.grey, 156 | ), 157 | label: 'Home', 158 | ), 159 | BottomNavigationBarItem( 160 | icon: Image.asset( 161 | 'assets/images/list.png', 162 | height: 25, 163 | width: 25, 164 | color: _selectedIndex == 1 165 | ? Theme.of(context).colorScheme.secondary 166 | : Colors.grey, 167 | ), 168 | label: 'Chat', 169 | ), 170 | BottomNavigationBarItem( 171 | icon: Image.asset( 172 | 'assets/images/categories.png', 173 | height: 25, 174 | width: 25, 175 | color: _selectedIndex == 2 176 | ? Theme.of(context).colorScheme.secondary 177 | : Colors.grey, 178 | ), 179 | label: 'Chat', 180 | ), 181 | BottomNavigationBarItem( 182 | icon: Stack( 183 | overflow: Overflow.visible, 184 | children: [ 185 | Image.asset( 186 | 'assets/images/chat.png', 187 | height: 30, 188 | width: 30, 189 | color: _selectedIndex == 3 190 | ? Theme.of(context).colorScheme.secondary 191 | : Colors.grey, 192 | ), 193 | Positioned( 194 | top: -1, 195 | right: 0, 196 | child: Container( 197 | height: 8, 198 | width: 8, 199 | decoration: BoxDecoration( 200 | shape: BoxShape.circle, 201 | color: Theme.of(context).colorScheme.primary, 202 | )), 203 | ) 204 | ], 205 | ), 206 | label: 'Chat', 207 | ), 208 | ], 209 | ), 210 | ), 211 | ); 212 | } 213 | 214 | void _onTappedBar(int value) { 215 | setState(() { 216 | _selectedIndex = value; 217 | }); 218 | _pageController.jumpToPage(value); 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /lib/pages/homepage.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: avoid_print 2 | 3 | import 'package:antdesign_icons/antdesign_icons.dart'; 4 | import 'package:cached_network_image/cached_network_image.dart'; 5 | import 'package:cloud_firestore/cloud_firestore.dart'; 6 | import 'package:firebase_auth/firebase_auth.dart' as auth; 7 | import 'package:flutter/cupertino.dart'; 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_bloc/flutter_bloc.dart'; 10 | import 'package:flutter_svg/flutter_svg.dart'; 11 | import 'package:geolocator/geolocator.dart'; 12 | import 'package:google_fonts/google_fonts.dart'; 13 | import 'package:latlng/latlng.dart'; 14 | import 'package:lottie/lottie.dart'; 15 | import 'package:provider/provider.dart'; 16 | import 'package:shared_preferences/shared_preferences.dart'; 17 | import 'package:shimmer/shimmer.dart'; 18 | import 'package:tiki/constatns/colors.dart'; 19 | import 'package:tiki/profile.dart'; 20 | import 'package:tiki/pages/tabs/userscreen.dart'; 21 | import 'package:tiki/providers/userdata.dart'; 22 | import 'package:tiki/respositories/bloc/swipebloc_bloc.dart'; 23 | import 'package:tiki/widgets/usercard.dart'; 24 | import '../models/user.dart'; 25 | 26 | class HomePage extends StatefulWidget { 27 | const HomePage({Key? key}) : super(key: key); 28 | 29 | @override 30 | _HomePageState createState() => _HomePageState(); 31 | } 32 | 33 | class _HomePageState extends State 34 | with AutomaticKeepAliveClientMixin { 35 | final bool isLike = false; 36 | final bool isHeart = false; 37 | TapDownDetails? detailes; 38 | @override 39 | void initState() { 40 | // TODO: implement initState 41 | super.initState(); 42 | getUser(); 43 | _getUserLocation(); 44 | } 45 | 46 | void saveUser(String imgeUrl) async { 47 | SharedPreferences prefs = await SharedPreferences.getInstance(); 48 | prefs.setString('user', imgeUrl); 49 | } 50 | 51 | UserData? userData; 52 | LatLng? currentPostion; 53 | Position? _currentLocation; 54 | 55 | void getCureentUserLocation() async { 56 | var position = await GeolocatorPlatform.instance 57 | .getCurrentPosition( 58 | locationSettings: 59 | const LocationSettings(accuracy: LocationAccuracy.high)) 60 | .then((value) => { 61 | setState(() { 62 | _currentLocation = value; 63 | }), 64 | }); 65 | } 66 | 67 | var userCrendentail = auth.FirebaseAuth.instance.currentUser; 68 | void _getUserLocation() async { 69 | var position = await GeolocatorPlatform.instance 70 | .getCurrentPosition( 71 | locationSettings: 72 | const LocationSettings(accuracy: LocationAccuracy.high)) 73 | .then((value) => { 74 | FirebaseFirestore.instance 75 | .collection('users') 76 | .doc(userCrendentail!.email) 77 | .update({ 78 | 'currentPostion': GeoPoint(value.latitude, value.longitude), 79 | }) 80 | }); 81 | } 82 | 83 | String? offlineUrl; 84 | void getUser() async { 85 | SharedPreferences prefs = await SharedPreferences.getInstance(); 86 | setState(() { 87 | offlineUrl = prefs.getString('user'); 88 | }); 89 | } 90 | 91 | final GlobalKey _scaffoldKey = GlobalKey(); 92 | User? user; 93 | @override 94 | Widget build(BuildContext context) { 95 | var userData = Provider.of(context); 96 | return Scaffold( 97 | key: _scaffoldKey, 98 | // drawer: DrawerWidget(), 99 | 100 | body: SafeArea( 101 | child: SingleChildScrollView( 102 | child: BlocBuilder( 103 | bloc: BlocProvider.of(context), 104 | builder: (context, state) { 105 | if (state is SwipeLoading) { 106 | return Column( 107 | crossAxisAlignment: CrossAxisAlignment.center, 108 | mainAxisAlignment: MainAxisAlignment.center, 109 | children: [ 110 | Row( 111 | crossAxisAlignment: CrossAxisAlignment.center, 112 | mainAxisAlignment: MainAxisAlignment.center, 113 | children: const [ 114 | CircularProgressIndicator(), 115 | ], 116 | ), 117 | ], 118 | ); 119 | } else if (state is SwipeLoaded) { 120 | return Padding( 121 | padding: const EdgeInsets.symmetric(vertical: 25.0), 122 | child: Column( 123 | children: [ 124 | InkWell( 125 | onTapDown: (details) { 126 | var position = details.globalPosition; 127 | if (position.dx < 128 | MediaQuery.of(context).size.width / 2) { 129 | print('left'); 130 | // tap left side 131 | 132 | } else { 133 | // tap rigth size 134 | 135 | print('right'); 136 | } 137 | }, 138 | onDoubleTap: () { 139 | Navigator.push( 140 | context, 141 | MaterialPageRoute( 142 | builder: (context) => 143 | ProfileScreen(user: state.users[0]))); 144 | }, 145 | child: FutureBuilder( 146 | future: userData.getData(), 147 | builder: (context, 148 | AsyncSnapshot snapshot) { 149 | if (snapshot.connectionState == 150 | ConnectionState.waiting) { 151 | return Center( 152 | child: CircularProgressIndicator(), 153 | ); 154 | } 155 | 156 | return Draggable( 157 | data: state.users[0], 158 | child: UserCard(user: state.users[0]), 159 | feedback: UserCard(user: state.users[0]), 160 | childWhenDragging: UserCard(user: state.users[1]), 161 | onDragEnd: (drag) { 162 | if (drag.velocity.pixelsPerSecond.dx < 0) { 163 | context.read().add( 164 | SwipeLeftEvent(user: state.users[0])); 165 | print('Swiped Left'); 166 | } else { 167 | context.read().add( 168 | SwipeRightEvent(user: state.users[0])); 169 | userData.saveLikedUser( 170 | currentUserAddress: 171 | snapshot.data!['location'], 172 | currentUserAge: snapshot.data!['age'], 173 | currentUsername: snapshot.data!['username'], 174 | currentUserImageurls: 175 | snapshot.data!['imageUrl'], 176 | currentUserInterest: 177 | snapshot.data!['interest'], 178 | currentoccupation: snapshot.data!['bio'], 179 | imageurls: state.users[0].imageUrls ?? [], 180 | likedUsername: state.users[0].name ?? '', 181 | likedUserAddress: 182 | state.users[0].location ?? '', 183 | likedUserage: state.users[0].age ?? '', 184 | likedUserInterest: 185 | state.users[0].interests ?? [], 186 | likedUseremail: state.users[0].email ?? '', 187 | occupation: state.users[0].bio ?? '', 188 | job: snapshot.data!['bio'], 189 | ); 190 | Future.delayed(const Duration(seconds: 2), 191 | () { 192 | Lottie.asset('assets/animations/love.json'); 193 | }); 194 | print('Swiped Right'); 195 | } 196 | }, 197 | ); 198 | }), 199 | ), 200 | const SizedBox( 201 | height: 10, 202 | ), 203 | ], 204 | ), 205 | ); 206 | } else if (state is SwipeError) { 207 | return const Center( 208 | child: Text('Error'), 209 | ); 210 | } else if (state is SwipeEmpty) { 211 | return const Center( 212 | child: Text('Empty'), 213 | ); 214 | } 215 | return const Text('Something went wrong'); 216 | }, 217 | )), 218 | ), 219 | ); 220 | } 221 | 222 | @override 223 | // TODO: implement wantKeepAlive 224 | bool get wantKeepAlive => true; 225 | } 226 | -------------------------------------------------------------------------------- /lib/pages/signin.dart: -------------------------------------------------------------------------------- 1 | import 'package:antdesign_icons/antdesign_icons.dart'; 2 | import 'package:eva_icons_flutter/eva_icons_flutter.dart'; 3 | import 'package:firebase_auth/firebase_auth.dart'; 4 | import 'package:flutter/cupertino.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_bloc/flutter_bloc.dart'; 7 | import 'package:google_fonts/google_fonts.dart'; 8 | import 'package:lottie/lottie.dart'; 9 | import 'package:tiki/authentications_bloc/cubits/signup_cubit.dart'; 10 | import 'package:tiki/instances/login_status.dart'; 11 | import 'package:tiki/pages/homepage.dart'; 12 | import 'package:tiki/pages/tabs/mainpage.dart'; 13 | import 'package:tiki/respositories/mainauth.dart'; 14 | import 'package:tiki/widgets/custom_textfield.dart'; 15 | import 'package:tiki/widgets/header.dart'; 16 | 17 | class SigninPage extends StatefulWidget { 18 | const SigninPage({Key? key}) : super(key: key); 19 | 20 | @override 21 | _SigninPageState createState() => _SigninPageState(); 22 | } 23 | 24 | class _SigninPageState extends State { 25 | final TextEditingController emailController = TextEditingController(); 26 | final TextEditingController passwordController = TextEditingController(); 27 | var formKey = GlobalKey(); 28 | String? error; 29 | AuthRepository? authRepository; 30 | @override 31 | Widget build(BuildContext context) { 32 | return Scaffold( 33 | appBar: AppBar( 34 | backgroundColor: Colors.transparent, 35 | elevation: 0, 36 | title: Padding( 37 | padding: const EdgeInsets.only(right: 60.0), 38 | child: Row( 39 | mainAxisAlignment: MainAxisAlignment.center, 40 | crossAxisAlignment: CrossAxisAlignment.center, 41 | children: [ 42 | Image.asset('assets/images/connect.png', 43 | height: 25, 44 | width: 25, 45 | color: Theme.of(context).colorScheme.secondary), 46 | const SizedBox(width: 5), 47 | Text( 48 | 'Discover', 49 | style: GoogleFonts.aBeeZee( 50 | fontSize: 20, 51 | fontWeight: FontWeight.bold, 52 | color: Theme.of(context).colorScheme.secondary, 53 | ), 54 | ), 55 | ])), 56 | centerTitle: true, 57 | ), 58 | body: Padding( 59 | padding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 50), 60 | child: Column( 61 | crossAxisAlignment: CrossAxisAlignment.start, 62 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 63 | children: [ 64 | Column( 65 | crossAxisAlignment: CrossAxisAlignment.start, 66 | children: [ 67 | SizedBox( 68 | height: MediaQuery.of(context).size.height / 11, 69 | ), 70 | 71 | // SizedBox( 72 | // height: 200, 73 | // width: 200, 74 | // child: Lottie.asset( 75 | // 'assets/animations/onboaring_love.json', 76 | // ), 77 | // ), 78 | RichText( 79 | text: TextSpan( 80 | text: 'Hey there,', 81 | style: GoogleFonts.aBeeZee( 82 | fontSize: 19, 83 | fontWeight: FontWeight.w500, 84 | color: Colors.grey, 85 | ), 86 | children: [ 87 | TextSpan( 88 | text: '\nWelcome back!', 89 | style: GoogleFonts.aBeeZee( 90 | fontSize: 20, 91 | fontWeight: FontWeight.bold, 92 | color: Colors.black, 93 | ), 94 | ) 95 | ]), 96 | ), 97 | SizedBox( 98 | height: MediaQuery.of(context).size.height * 0.1, 99 | ), 100 | Form( 101 | key: formKey, 102 | child: Column( 103 | children: [ 104 | TextFormField( 105 | controller: emailController, 106 | validator: (value) { 107 | if (value!.isEmpty) { 108 | return 'Email is required'; 109 | } 110 | }, 111 | decoration: InputDecoration( 112 | suffixIcon: const Icon(Icons.mail), 113 | filled: true, 114 | fillColor: Colors.white, 115 | border: InputBorder.none, 116 | hintText: 'Email', 117 | hintStyle: GoogleFonts.aBeeZee( 118 | color: Colors.grey, 119 | fontSize: 14, 120 | ), 121 | ), 122 | ), 123 | const SizedBox( 124 | height: 20, 125 | ), 126 | TextFormField( 127 | controller: passwordController, 128 | obscureText: true, 129 | validator: (value) { 130 | if (value!.isEmpty) { 131 | return 'Password is required'; 132 | } 133 | }, 134 | decoration: InputDecoration( 135 | filled: true, 136 | suffixIcon: const Icon(AntIcons.lockFilled), 137 | fillColor: Colors.white, 138 | border: InputBorder.none, 139 | hintText: 'Password', 140 | hintStyle: GoogleFonts.aBeeZee( 141 | color: Colors.grey, 142 | fontSize: 14, 143 | ), 144 | ), 145 | ), 146 | const SizedBox( 147 | height: 10, 148 | ), 149 | Column( 150 | children: [ 151 | Padding( 152 | padding: const EdgeInsets.only(left: 210.0), 153 | child: Text( 154 | 'Forgot Password?', 155 | style: GoogleFonts.aBeeZee( 156 | color: Colors.grey, 157 | fontSize: 14, 158 | ), 159 | ), 160 | ) 161 | ], 162 | ) 163 | ], 164 | ), 165 | ), 166 | ], 167 | ), 168 | DecoratedBox( 169 | decoration: BoxDecoration( 170 | borderRadius: BorderRadius.circular(5), 171 | gradient: LinearGradient( 172 | colors: [ 173 | Theme.of(context).accentColor, 174 | Theme.of(context).primaryColor, 175 | ], 176 | ), 177 | ), 178 | child: ElevatedButton( 179 | onPressed: () { 180 | if (formKey.currentState!.validate()) { 181 | try { 182 | FirebaseAuth.instance 183 | .signInWithEmailAndPassword( 184 | email: emailController.text, 185 | password: passwordController.text) 186 | .then((value) { 187 | if (value == null) { 188 | print('error'); 189 | } else { 190 | Instances.saveLoginStatus('loggedIn'); 191 | Navigator.pushReplacement( 192 | context, 193 | CupertinoPageRoute( 194 | builder: (context) => const MainPage(), 195 | )); 196 | } 197 | }); 198 | } on FirebaseAuthException catch (e) { 199 | if (e.code == 'weak-password') { 200 | error = 'The password provided is too weak.'; 201 | 202 | print('The password provided is too weak.'); 203 | } else if (e.code == 'email-already-in-use') { 204 | setState(() { 205 | error = 'The account already exists for that email.'; 206 | }); 207 | 208 | print('The account already exists for that email.'); 209 | } else if (e.code == 'wrong-password') { 210 | setState(() { 211 | error = "Wrong password provided for that user."; 212 | }); 213 | } else if (e.code == 'user-not-found') { 214 | setState(() { 215 | error = 'No user found for that email.'; 216 | }); 217 | } else { 218 | error = 219 | 'you are currently offline, please reconnect to internet'; 220 | } 221 | } catch (e) { 222 | error = e.toString(); 223 | showDialog( 224 | context: context, 225 | builder: (context) { 226 | return AlertDialog( 227 | title: Text('Error'), 228 | content: Text(error!), 229 | actions: [ 230 | FlatButton( 231 | child: Text('OK'), 232 | onPressed: () { 233 | Navigator.pop(context); 234 | }, 235 | ) 236 | ], 237 | ); 238 | }); 239 | 240 | print(e); 241 | } 242 | } 243 | }, 244 | style: ElevatedButton.styleFrom( 245 | primary: Colors.transparent, 246 | elevation: 0, 247 | ), 248 | child: SizedBox( 249 | width: double.infinity, 250 | child: Center( 251 | child: Text('Sign In', 252 | style: GoogleFonts.aBeeZee( 253 | fontSize: 15, 254 | fontWeight: FontWeight.w600, 255 | )), 256 | ), 257 | ), 258 | ), 259 | ), 260 | ], 261 | ), 262 | ), 263 | ); 264 | } 265 | } 266 | --------------------------------------------------------------------------------