diff --git a/undomain/.env b/undomain/.env new file mode 100644 index 0000000..54aaf25 --- /dev/null +++ b/undomain/.env @@ -0,0 +1,2 @@ +ZEGO_APPID=28439340 +ZEGO_APPSING=fa42963266224d38a78401e3266172c17468fdf478797b1d5cda2aadc52ff90d \ No newline at end of file diff --git a/undomain/.gitignore b/undomain/.gitignore index 79c113f..a7e49bb 100644 --- a/undomain/.gitignore +++ b/undomain/.gitignore @@ -11,7 +11,7 @@ .svn/ .swiftpm/ migrate_working_dir/ - +/secrets/ # IntelliJ related *.iml *.ipr diff --git a/undomain/android/app/build.gradle.kts b/undomain/android/app/build.gradle.kts index 3cca62d..a69b2d3 100644 --- a/undomain/android/app/build.gradle.kts +++ b/undomain/android/app/build.gradle.kts @@ -7,7 +7,7 @@ plugins { android { namespace = "com.example.undomain" - compileSdk = 35 + compileSdk = 34 ndkVersion = flutter.ndkVersion @@ -25,7 +25,7 @@ android { applicationId = "com.example.undomain" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. - minSdk = 22 + minSdk = 23 targetSdk = flutter.targetSdkVersion versionCode = flutter.versionCode versionName = flutter.versionName @@ -36,6 +36,9 @@ android { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. signingConfig = signingConfigs.getByName("debug") + + proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") + } } } @@ -43,3 +46,6 @@ android { flutter { source = "../.." } +// dependencies { +// implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" +// } \ No newline at end of file diff --git a/undomain/android/app/proguard-rules.pro b/undomain/android/app/proguard-rules.pro new file mode 100644 index 0000000..963122d --- /dev/null +++ b/undomain/android/app/proguard-rules.pro @@ -0,0 +1 @@ +-keep class **.zego.** { *; } diff --git a/undomain/android/app/src/main/AndroidManifest.xml b/undomain/android/app/src/main/AndroidManifest.xml index bc69e72..6fc49ad 100644 --- a/undomain/android/app/src/main/AndroidManifest.xml +++ b/undomain/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,13 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/undomain/assets/livetext.svg b/undomain/assets/livetext.svg new file mode 100644 index 0000000..00a8e94 --- /dev/null +++ b/undomain/assets/livetext.svg @@ -0,0 +1,4 @@ + + + + diff --git a/undomain/assets/mess.jpeg b/undomain/assets/mess.jpeg new file mode 100644 index 0000000..fe7535d Binary files /dev/null and b/undomain/assets/mess.jpeg differ diff --git a/undomain/assets/pic.jpg b/undomain/assets/pic.jpg new file mode 100644 index 0000000..e9892c4 Binary files /dev/null and b/undomain/assets/pic.jpg differ diff --git a/undomain/lib/main.dart b/undomain/lib/main.dart index 1c68576..da7ce74 100644 --- a/undomain/lib/main.dart +++ b/undomain/lib/main.dart @@ -1,8 +1,15 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:undomain/pages/restart/restart.dart'; import 'package:undomain/router/go_router.dart'; +import 'package:zego_uikit_prebuilt_live_streaming/zego_uikit_prebuilt_live_streaming.dart'; -void main() { - runApp(const MyApp()); +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + //initialize zego cloud + await ZegoUIKit().initLog().then((value) { + runApp(RestartWidget(child: ProviderScope(child: const MyApp()))); + }); } class MyApp extends StatelessWidget { diff --git a/undomain/lib/models/user/user_model.dart b/undomain/lib/models/user/user_model.dart index 0f30ea1..5759dd6 100644 --- a/undomain/lib/models/user/user_model.dart +++ b/undomain/lib/models/user/user_model.dart @@ -1,5 +1,5 @@ class UserModel { - final String uid; + final String id; final String username; final String password; final String email; @@ -9,10 +9,13 @@ class UserModel { final DateTime updatedDate; final String serviceDiscription; final String? bio; - final List? followers; - final List? following; + final List? followers; + final List? following; final int? contact; final String? referenceUrl; + final bool? isVerified; + final String? verifyCode; + final int? codeExpireTime; UserModel({ required this.contact, required this.referenceUrl, @@ -25,17 +28,20 @@ class UserModel { required this.serviceDiscription, required this.profileUrl, - required this.uid, + required this.id, required this.username, required this.password, required this.email, required this.isCreator, + required this.isVerified, + required this.verifyCode, + required this.codeExpireTime, }); // convert to json object Map toJson() { return { - "uid": uid, + "id": id, "username": username, "email": email, "profileUrl": profileUrl, @@ -49,27 +55,33 @@ class UserModel { "referenceUrl": referenceUrl, "followers": followers, "following": following, + "isVerified": isVerified, + "verifyCode": verifyCode, + "codeExpireTime": codeExpireTime, }; } //convert from json object factory UserModel.fromJson(Map json) { return UserModel( - uid: json["uid"], + id: json["_id"], username: json["username"], serviceDiscription: json["serviceDiscription"] ?? "", email: json["email"], password: json["password"], - joinedDate: json["joinedDate"], - updatedDate: json["updatedDate"], - profileUrl: json["image"] ?? "", + joinedDate: DateTime.parse(json["createdAt"]), + updatedDate: DateTime.parse(json["updatedAt"]), + profileUrl: json["profileUrl"] ?? "", followers: json["followers"] ?? [], following: json["followings"] ?? [], bio: json["bio"] ?? "", - contact: json["contact"] ?? "", + contact: json["contact"] ?? 0, isCreator: json["isCreator"], referenceUrl: json["referenceUrl"] ?? "", + isVerified: json["isVerified"], + verifyCode: json["verifyCode"] ?? "", + codeExpireTime: json["codeExpireTime"] ?? 0, ); } } diff --git a/undomain/lib/pages/authentication/email_verification/email_verification.dart b/undomain/lib/pages/authentication/email_verification/email_verification.dart index 6299109..3c2627a 100644 --- a/undomain/lib/pages/authentication/email_verification/email_verification.dart +++ b/undomain/lib/pages/authentication/email_verification/email_verification.dart @@ -3,13 +3,25 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:pinput/pinput.dart'; +import 'package:undomain/pages/restart/restart.dart'; import 'package:undomain/router/router_names.dart'; +import 'package:undomain/services/auth_services/authservices.dart'; +import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/global/global_function.dart'; import 'package:undomain/util/global/global_varibles.dart'; import 'package:undomain/util/textstyles/text_styles.dart'; import 'package:undomain/widgets/buttons/authpage_button.dart'; class EmailVerification extends StatefulWidget { - const EmailVerification({super.key}); + final String userid; + final bool isForRegister; + final String? email; + const EmailVerification({ + super.key, + required this.userid, + required this.isForRegister, + this.email, + }); @override State createState() => _EmailVerificationState(); @@ -18,7 +30,10 @@ class EmailVerification extends StatefulWidget { class _EmailVerificationState extends State { late Timer _timer; int _start = 60; - + bool _isLoading = false; + final TextEditingController _pincontroller = TextEditingController(); + final GlobalFunction _globalFunction = GlobalFunction(); + final Authservices _authservices = Authservices(); @override void initState() { startTimer(); @@ -44,9 +59,44 @@ class _EmailVerificationState extends State { }); } - void _onSubmit(String pin) { - // Validate or verify PIN here - print("Entered Code: $pin"); + //request when complete the pinput + void _onSubmit(String pin) async { + setState(() { + _isLoading = true; + }); + if (pin.isEmpty || widget.userid.isEmpty) { + _globalFunction.snackBarMassage(context, "Empty User Data", 3); + return; + } + + //for user registration + if (widget.isForRegister) { + final response = await _authservices.verifyNewUser( + userId: widget.userid, + verifyCode: pin, + ); + if (response["success"]) { + RestartWidget.restartApp(context); + } else { + _globalFunction.snackBarMassage(context, response["massage"], 3); + } + //for password reset + } else { + final response = await _authservices.verifyResetPassword( + email: widget.email!, + otp: pin, + password: widget.userid, + ); + if (response["success"]) { + GoRouter.of(context).goNamed(RouterNames.loginPage); + } else { + _globalFunction.snackBarMassage(context, response["massage"], 3); + } + } + setState(() { + _isLoading = false; + _pincontroller.clear(); + }); } @override @@ -55,13 +105,21 @@ class _EmailVerificationState extends State { final defaultPinTheme = PinTheme( width: (pinputSize - 0.08) / 5, height: (pinputSize - 0.08) / 5, - textStyle: TextStyle(fontSize: 20, color: Colors.black), + textStyle: TextStyle(fontSize: 20, color: utilPrimaryBlack), decoration: BoxDecoration( - border: Border.all(color: Colors.grey), borderRadius: BorderRadius.circular(10), + color: utilPrimaryWhite, + boxShadow: [ + BoxShadow( + offset: Offset(1, 2), + blurRadius: 2, + color: utilPrimaryGrey.withOpacity(0.5), + ), + ], ), ); return Scaffold( + resizeToAvoidBottomInset: false, body: Padding( padding: EdgeInsets.symmetric( horizontal: authScreenPaddingH, @@ -70,7 +128,6 @@ class _EmailVerificationState extends State { child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - //SizedBox(height: MediaQuery.of(context).size.height * 0.01), //title Text("Date NET.", style: textDisplay), Column( @@ -80,6 +137,7 @@ class _EmailVerificationState extends State { SizedBox(height: MediaQuery.of(context).size.height * 0.02), //pinputs Pinput( + controller: _pincontroller, length: 5, keyboardType: TextInputType.number, onCompleted: _onSubmit, @@ -96,14 +154,20 @@ class _EmailVerificationState extends State { ], ), ) - : Text("Resend", style: textLabel), + : TextButton( + onPressed: () {}, + child: Text("Resend", style: textLabelRed), + ), ], ), SizedBox(height: MediaQuery.of(context).size.height * 0.08), Column( children: [ //verify button:to home page - AuthpageButton(path: RouterNames.homePage, text: "Verify"), + GestureDetector( + onTap: () => _onSubmit(_pincontroller.text), + child: AuthpageButton(text: "Verify", isLoading: _isLoading), + ), //to login page TextButton( onPressed: () { diff --git a/undomain/lib/pages/authentication/fogotpassword/fogot_password.dart b/undomain/lib/pages/authentication/fogotpassword/fogot_password.dart new file mode 100644 index 0000000..e5db645 --- /dev/null +++ b/undomain/lib/pages/authentication/fogotpassword/fogot_password.dart @@ -0,0 +1,185 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:undomain/router/router_names.dart'; +import 'package:undomain/services/auth_services/authservices.dart'; +import 'package:undomain/util/global/global_function.dart'; +import 'package:undomain/util/global/global_varibles.dart'; +import 'package:undomain/util/textstyles/text_styles.dart'; +import 'package:undomain/widgets/buttons/authpage_button.dart'; +import 'package:undomain/widgets/textboxes/authtext_box.dart'; + +class FogotPassword extends StatefulWidget { + const FogotPassword({super.key}); + + @override + State createState() => _FogotPasswordState(); +} + +class _FogotPasswordState extends State { + final TextEditingController _confirmpasswordcontroller = + TextEditingController(); + final TextEditingController _passwordcontroller = TextEditingController(); + final TextEditingController _emailcontroller = TextEditingController(); + final _formKey = GlobalKey(); + bool _isLoading = false; + final Authservices _authservices = Authservices(); + final GlobalFunction _globalFunction = GlobalFunction(); + //regexp for password + final RegExp passwordRegExp = RegExp( + r'^(?=.*[A-Za-z])(?=.*\d)(?=.*[!@#$%^&*(),.?":{}|<>]).{6,}$', + ); + String confirmpasswordHint = "@confirm password"; + bool isconfirmpasswordValid = true; + String passwordHint = "@password"; + String emailHint = "@email"; + bool isPasswordValid = true; + + Future _getCodeForResetPassword() async { + setState(() { + _isLoading = true; + }); + + final response = await _authservices.sendPasswordResetRequest( + email: _emailcontroller.text, + ); + if (response["success"]) { + GoRouter.of(context).goNamed( + RouterNames.verificationPage, + extra: { + "userId": _passwordcontroller.text, + "isFromRegister": false, + "email": response["user"]["id"], + }, + ); + } else { + _globalFunction.snackBarMassage(context, response["massage"], 3); + } + setState(() { + _isLoading = false; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + resizeToAvoidBottomInset: false, + body: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: authScreenPaddingH, + vertical: authScreenPaddingV, + ), + child: Column( + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.08), + //title + Column(children: [Text("Date NET.", style: textDisplay)]), + SizedBox(height: MediaQuery.of(context).size.height * 0.15), + //auth details + Form( + key: _formKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + //password + AuthtextBox( + isValid: isPasswordValid, + controller: _emailcontroller, + hint: emailHint, + isShow: false, + onSubmit: (p0) {}, + textInputAction: TextInputAction.next, + textInputType: TextInputType.emailAddress, + + validChecker: (value) => null, + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.02), + AuthtextBox( + isValid: isPasswordValid, + controller: _passwordcontroller, + hint: passwordHint, + isShow: false, + onSubmit: (p0) {}, + textInputAction: TextInputAction.next, + textInputType: TextInputType.name, + + validChecker: (value) => null, + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.02), + //confirm password + AuthtextBox( + controller: _confirmpasswordcontroller, + isValid: isconfirmpasswordValid, + hint: confirmpasswordHint, + isShow: false, + onSubmit: (p0) {}, + textInputAction: TextInputAction.done, + textInputType: TextInputType.visiblePassword, + validChecker: (value) => null, + ), + + SizedBox(height: MediaQuery.of(context).size.height * 0.25), + Column( + children: [ + //if valid form state + GestureDetector( + onTap: () async { + if (_confirmpasswordcontroller.text.isEmpty && + _passwordcontroller.text.isEmpty) { + setState(() { + isPasswordValid = false; + passwordHint = "please enter your @password"; + isconfirmpasswordValid = false; + confirmpasswordHint = + "please confirm your password"; + }); + } else if (!passwordRegExp.hasMatch( + _passwordcontroller.text, + )) { + setState(() { + passwordHint = "weak password"; + _passwordcontroller.clear(); + }); + } else if (_passwordcontroller.text != + _confirmpasswordcontroller.text) { + setState(() { + confirmpasswordHint = + "password mismatching please check your password"; + _confirmpasswordcontroller.clear(); + }); + } else { + await _getCodeForResetPassword(); + } + }, + + child: AuthpageButton( + text: "Submit", + isLoading: false, + ), + ), + //to register page + TextButton( + onPressed: () { + GoRouter.of( + context, + ).goNamed(RouterNames.registerPage); + }, + child: Text( + "Create new account", + style: textLabelRed, + ), + ), + ], + ), + + //to home page + ], + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/undomain/lib/pages/authentication/login/login_screen.dart b/undomain/lib/pages/authentication/login/login_screen.dart index 5910e57..b1c04d4 100644 --- a/undomain/lib/pages/authentication/login/login_screen.dart +++ b/undomain/lib/pages/authentication/login/login_screen.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:undomain/pages/restart/restart.dart'; import 'package:undomain/router/router_names.dart'; +import 'package:undomain/services/auth_services/authservices.dart'; +import 'package:undomain/util/global/global_function.dart'; import 'package:undomain/util/global/global_varibles.dart'; import 'package:undomain/util/textstyles/text_styles.dart'; import 'package:undomain/widgets/buttons/authpage_button.dart'; @@ -16,7 +19,10 @@ class LoginScreen extends StatefulWidget { class _LoginScreenState extends State { final TextEditingController _usernamecontroller = TextEditingController(); final TextEditingController _passwordcontroller = TextEditingController(); - + final _formKey = GlobalKey(); + bool _isLoading = false; + final GlobalFunction _globalFunction = GlobalFunction(); + final Authservices _authservices = Authservices(); @override void dispose() { _passwordcontroller.dispose(); @@ -24,9 +30,35 @@ class _LoginScreenState extends State { super.dispose(); } + Future _userLogin() async { + setState(() { + _isLoading = true; + }); + + final response = await _authservices.login( + username: _usernamecontroller.text, + password: _passwordcontroller.text, + ); + if (response["success"]) { + //restart app + RestartWidget.restartApp(context); + } else { + _globalFunction.snackBarMassage(context, response["massage"], 3); + } + setState(() { + _isLoading = false; + }); + } + + //login validation frontend properties + String usernameHint = "@username"; + bool isUsernameValid = true; + String passwordHint = "@password"; + bool isPasswordValid = true; @override Widget build(BuildContext context) { return Scaffold( + resizeToAvoidBottomInset: false, body: SingleChildScrollView( child: Padding( padding: EdgeInsets.symmetric( @@ -41,33 +73,65 @@ class _LoginScreenState extends State { SizedBox(height: MediaQuery.of(context).size.height * 0.15), //auth details Form( + key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AuthtextBox( + isValid: isUsernameValid, controller: _usernamecontroller, - hint: "@username", + hint: usernameHint, isShow: false, onSubmit: (p0) {}, textInputAction: TextInputAction.next, textInputType: TextInputType.name, + + validChecker: (value) => null, ), SizedBox(height: MediaQuery.of(context).size.height * 0.02), //password AuthtextBox( controller: _passwordcontroller, - hint: "@password", + isValid: isPasswordValid, + hint: passwordHint, isShow: false, onSubmit: (p0) {}, textInputAction: TextInputAction.done, textInputType: TextInputType.visiblePassword, + validChecker: (value) => null, ), - SizedBox(height: MediaQuery.of(context).size.height * 0.3), + SizedBox(height: MediaQuery.of(context).size.height * 0.01), + TextButton( + onPressed: () { + GoRouter.of( + context, + ).goNamed(RouterNames.fogotpasswordScreen); + }, + child: Text("Fogot Password ?", style: textLabelRed), + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.25), Column( children: [ - AuthpageButton( - text: "Login", - path: RouterNames.homePage, + //if valid form state + GestureDetector( + onTap: () async { + if (_formKey.currentState!.validate() && + _usernamecontroller.text.isNotEmpty && + _passwordcontroller.text.isNotEmpty) { + await _userLogin(); + } else { + setState(() { + isPasswordValid = false; + passwordHint = "please enter your @password"; + isUsernameValid = false; + usernameHint = "please enter your @username"; + }); + } + }, + child: AuthpageButton( + text: "Login", + isLoading: _isLoading, + ), ), //to register page TextButton( diff --git a/undomain/lib/pages/authentication/register/register_screen.dart b/undomain/lib/pages/authentication/register/register_screen.dart index 23d6a7b..527fd2d 100644 --- a/undomain/lib/pages/authentication/register/register_screen.dart +++ b/undomain/lib/pages/authentication/register/register_screen.dart @@ -1,7 +1,13 @@ +import 'dart:io'; + +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:undomain/router/router_names.dart'; +import 'package:undomain/services/auth_services/authservices.dart'; import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/global/global_function.dart'; import 'package:undomain/util/global/global_varibles.dart'; import 'package:undomain/util/textstyles/text_styles.dart'; import 'package:undomain/widgets/buttons/authpage_button.dart'; @@ -20,6 +26,11 @@ class _RegisterScreenState extends State { final TextEditingController _confirmpasswordcontroller = TextEditingController(); final TextEditingController _emailcontroller = TextEditingController(); + final _formKey = GlobalKey(); + final Authservices _authservices = Authservices(); + final GlobalFunction _globalFunction = GlobalFunction(); + File? _file; + bool _isLoading = false; @override void dispose() { _passwordcontroller.dispose(); @@ -29,82 +40,239 @@ class _RegisterScreenState extends State { super.dispose(); } + //regexp for password + final RegExp passwordRegExp = RegExp( + r'^(?=.*[A-Za-z])(?=.*\d)(?=.*[!@#$%^&*(),.?":{}|<>]).{6,}$', + ); + + //reg exp for username + final RegExp usernameRegExp = RegExp(r'[!@#$%^&*(),.?":{}|<>]'); + + ///regexp for email + final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$'); + + //login validation frontend properties + String usernameHint = "@username"; + bool isUsernameValid = true; + String passwordHint = "@password"; + bool isPasswordValid = true; + String emailHint = "@email"; + bool isEmailValid = true; + String confirmPasswordHint = "@confirm password"; + bool isConfirmPasswordValid = true; + + //set profile image + Future _setProfileImage(ImageSource source) async { + ImagePicker _imgPicker = ImagePicker(); + final image = await _imgPicker.pickImage(source: source); + if (image != null) { + setState(() { + _file = File(image.path); + }); + } + } + + //save valid user data and get verifcation code + Future userRegister() async { + setState(() { + _isLoading = true; + }); + + final response = await _authservices.register( + _file!, + username: _usernamecontroller.text, + email: _emailcontroller.text, + password: _passwordcontroller.text, + ); + if (response["succss"]) { + GoRouter.of(context).goNamed( + RouterNames.verificationPage, + extra: { + "userId": response["user"]["id"], + "isFromRegister": true, + "email": "", + }, + ); + } else { + _globalFunction.snackBarMassage(context, response["massage"], 3); + } + setState(() { + _isLoading = false; + }); + } + @override Widget build(BuildContext context) { return Scaffold( - body: Padding( - padding: EdgeInsets.symmetric( - horizontal: authScreenPaddingH, - vertical: authScreenPaddingV, - ), - child: Column( - children: [ - SizedBox(height: MediaQuery.of(context).size.height * 0.08), - //title - Text("Date NET.", style: textDisplay), - //auth details - Form( - child: Column( - children: [ - SizedBox(height: MediaQuery.of(context).size.height * 0.02), - CircleAvatar(backgroundColor: utilPrimaryGrey, radius: 64), - SizedBox(height: MediaQuery.of(context).size.height * 0.02), - //username - AuthtextBox( - controller: _usernamecontroller, - hint: "@username", - isShow: false, - onSubmit: (p0) {}, - textInputAction: TextInputAction.next, - textInputType: TextInputType.name, - ), - SizedBox(height: MediaQuery.of(context).size.height * 0.02), - //email - AuthtextBox( - controller: _passwordcontroller, - hint: "@email", - isShow: false, - onSubmit: (p0) {}, - textInputAction: TextInputAction.next, - textInputType: TextInputType.emailAddress, - ), - SizedBox(height: MediaQuery.of(context).size.height * 0.02), - //password - AuthtextBox( - controller: _confirmpasswordcontroller, - hint: "@password", - isShow: false, - onSubmit: (p0) {}, - textInputAction: TextInputAction.next, - textInputType: TextInputType.visiblePassword, - ), - SizedBox(height: MediaQuery.of(context).size.height * 0.02), - //password - AuthtextBox( - controller: _emailcontroller, - hint: "@password", - isShow: false, - onSubmit: (p0) {}, - textInputAction: TextInputAction.done, - textInputType: TextInputType.visiblePassword, - ), - SizedBox(height: MediaQuery.of(context).size.height * 0.08), - //to verification page - AuthpageButton( - text: "Register", - path: RouterNames.verificationPage, - ), - //to login page - TextButton( - onPressed: () { - GoRouter.of(context).goNamed(RouterNames.loginPage); - }, - child: Text("Login", style: textLabelRed), - ), - ], + // resizeToAvoidBottomInset: false, + body: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: authScreenPaddingH, + vertical: authScreenPaddingV, + ), + child: Column( + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.08), + //title + Text("Date NET.", style: textDisplay), + //auth details + Form( + key: _formKey, + child: Column( + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.02), + Stack( + children: [ + //profile picture + _file != null + ? CircleAvatar( + backgroundImage: FileImage(_file!), + backgroundColor: utilPrimaryWhite.withOpacity( + 0.8, + ), + radius: 64, + ) + : CircleAvatar( + backgroundColor: utilPrimaryWhite.withOpacity( + 0.8, + ), + radius: 64, + ), + Positioned( + bottom: 0, + right: -6, + child: IconButton( + onPressed: () { + _setProfileImage(ImageSource.gallery); + }, + icon: Icon( + CupertinoIcons.camera_circle, + color: utilPrimaryWhite, + size: 40, + ), + ), + ), + ], + ), + + SizedBox(height: MediaQuery.of(context).size.height * 0.02), + //username + AuthtextBox( + isValid: isUsernameValid, + controller: _usernamecontroller, + hint: usernameHint, + isShow: false, + onSubmit: (p0) {}, + textInputAction: TextInputAction.next, + textInputType: TextInputType.name, + validChecker: (value) => null, + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.02), + //email + AuthtextBox( + isValid: isEmailValid, + controller: _emailcontroller, + hint: emailHint, + isShow: false, + onSubmit: (p0) {}, + textInputAction: TextInputAction.next, + textInputType: TextInputType.emailAddress, + validChecker: (value) => null, + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.02), + //password + AuthtextBox( + isValid: isPasswordValid, + controller: _passwordcontroller, + hint: passwordHint, + isShow: false, + onSubmit: (p0) {}, + textInputAction: TextInputAction.next, + textInputType: TextInputType.visiblePassword, + validChecker: (value) => null, + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.02), + //password + AuthtextBox( + isValid: isConfirmPasswordValid, + controller: _confirmpasswordcontroller, + hint: confirmPasswordHint, + isShow: false, + onSubmit: (p0) {}, + textInputAction: TextInputAction.done, + textInputType: TextInputType.visiblePassword, + validChecker: (value) => null, + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.08), + //to verification page + GestureDetector( + onTap: () async { + if (_usernamecontroller.text.isEmpty || + _emailcontroller.text.isEmpty || + _passwordcontroller.text.isEmpty || + _confirmpasswordcontroller.text.isEmpty) { + setState(() { + isUsernameValid = false; + isEmailValid = false; + isPasswordValid = false; + isConfirmPasswordValid = false; + usernameHint = "please enter your @username"; + emailHint = "please enter your @email"; + passwordHint = "please enter your @password"; + confirmPasswordHint = + "please enter your @confirm password"; + }); + } else if (usernameRegExp.hasMatch( + _usernamecontroller.text, + )) { + setState(() { + usernameHint = "@username cannot cantain symbols"; + _usernamecontroller.clear(); + }); + } else if (!emailRegex.hasMatch( + _emailcontroller.text, + )) { + setState(() { + emailHint = "Invalid @email format"; + _emailcontroller.clear(); + }); + } else if (!passwordRegExp.hasMatch( + _passwordcontroller.text, + )) { + setState(() { + passwordHint = "weak password"; + _passwordcontroller.clear(); + }); + } else if (_passwordcontroller.text != + _confirmpasswordcontroller.text) { + setState(() { + confirmPasswordHint = + "password mismatching please check your password"; + _confirmpasswordcontroller.clear(); + }); + } else { + //execute register function + await userRegister(); + } + }, + child: AuthpageButton( + text: "Register", + isLoading: _isLoading, + ), + ), + //to login page + TextButton( + onPressed: () { + GoRouter.of(context).goNamed(RouterNames.loginPage); + }, + child: Text("Login", style: textLabelRed), + ), + ], + ), ), - ), - ], + ], + ), ), ), ); diff --git a/undomain/lib/pages/authentication/spalshscreen/spalsh.dart b/undomain/lib/pages/authentication/spalshscreen/spalsh.dart index 23e1e5b..458e170 100644 --- a/undomain/lib/pages/authentication/spalshscreen/spalsh.dart +++ b/undomain/lib/pages/authentication/spalshscreen/spalsh.dart @@ -1,8 +1,15 @@ import 'dart:async'; +import 'package:animated_splash_screen/animated_splash_screen.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:page_transition/page_transition.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:undomain/pages/authentication/login/login_screen.dart'; +import 'package:undomain/pages/authentication/terms&conditions/terms_and_conditions.dart'; +import 'package:undomain/pages/home/main_screen.dart'; import 'package:undomain/router/router_names.dart'; +import 'package:undomain/util/colors/colors.dart'; import 'package:undomain/util/textstyles/text_styles.dart'; class SpalshScreen extends StatefulWidget { @@ -17,28 +24,61 @@ class _SpalshScreenState extends State { void initState() { super.initState(); Timer(Duration(seconds: 3), () { - GoRouter.of(context).goNamed(RouterNames.termsAndConditions); + GoRouter.of(context).goNamed(RouterNames.wrapperScreen); }); } + dynamic get splash => null; @override Widget build(BuildContext context) { - - return Scaffold( - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text("Date NET.", style: textDisplay), - SizedBox(height: 20), - - SizedBox(height: 10), - CircularProgressIndicator( - color: Colors.blue, - ), // optional loading spinner - ], - ), - ), + return AnimatedSplashScreen( + splash: Text("Date NET.", style: textDisplay), + nextScreen: WrapperScreen(), + // animationDuration: Duration(seconds: 3000), + backgroundColor: utilPrimaryWhite, + centered: true, + splashTransition: SplashTransition.fadeTransition, + pageTransitionType: PageTransitionType.fade, + + duration: 3000, ); } } + +//chack auth states +class WrapperScreen extends StatefulWidget { + const WrapperScreen({super.key}); + + @override + State createState() => _WrapperScreenState(); +} + +class _WrapperScreenState extends State { + bool isLoged = false; + bool isInitUser = false; + String? userId; + @override + void initState() { + _checkLoginState(); + super.initState(); + } + + void _checkLoginState() async { + SharedPreferences _pref = await SharedPreferences.getInstance(); + String? token = _pref.getString("token"); + userId = _pref.getString("user"); + setState(() { + isLoged = token != null; + isInitUser = userId == null; + }); + } + + @override + Widget build(BuildContext context) { + return isInitUser + ? TermsAndConditions() + : isLoged + ? Homepage(isFromLogin: false,index: 0,) + : LoginScreen(); + } +} diff --git a/undomain/lib/pages/authentication/terms&conditions/terms_and_conditions.dart b/undomain/lib/pages/authentication/terms&conditions/terms_and_conditions.dart index f589af5..763cc65 100644 --- a/undomain/lib/pages/authentication/terms&conditions/terms_and_conditions.dart +++ b/undomain/lib/pages/authentication/terms&conditions/terms_and_conditions.dart @@ -1,14 +1,21 @@ import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import 'package:undomain/router/router_names.dart'; import 'package:undomain/util/colors/colors.dart'; import 'package:undomain/util/global/global_varibles.dart'; import 'package:undomain/util/textstyles/text_styles.dart'; import 'package:undomain/widgets/buttons/authpage_button.dart'; -class TermsAndConditions extends StatelessWidget { +class TermsAndConditions extends StatefulWidget { const TermsAndConditions({super.key}); @override + State createState() => _TermsAndConditionsState(); +} + +class _TermsAndConditionsState extends State { + @override + bool isChecked = false; Widget build(BuildContext context) { final deviceWidth = MediaQuery.of(context).size.width; final deviceHeight = MediaQuery.of(context).size.height; @@ -39,20 +46,47 @@ class TermsAndConditions extends StatelessWidget { children: [ Row( children: [ + //acceptent check box Checkbox( - value: false, - onChanged: (value) {}, - checkColor: utilPrimaryRed, + value: isChecked, + activeColor: utilPrimaryRed, + onChanged: (value) { + setState(() { + isInitialUser = true; + isChecked = !isChecked; + }); + }, + checkColor: utilPrimaryWhite, autofocus: true, focusColor: utilPrimaryRed, side: BorderSide(color: utilPrimaryBlack, width: 1), ), Text("I agree terms & conditions", style: textLabel), - - //go to login page ], ), - AuthpageButton(path: RouterNames.loginPage, text: "Continue"), + //route to login page + GestureDetector( + onTap: () { + isChecked + ? GoRouter.of(context).goNamed(RouterNames.loginPage) + : ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: utilPrimaryRed, + closeIconColor: utilPrimaryWhite, + elevation: 1, + showCloseIcon: true, + padding: EdgeInsets.symmetric( + horizontal: authScreenPaddingH, + ), + content: Text( + "Please accept terms & conditions", + style: textSnackbar, + ), + ), + ); + }, + child: AuthpageButton(text: "Continue", isLoading: false), + ), ], ), ], diff --git a/undomain/lib/pages/home/home_screen.dart b/undomain/lib/pages/home/home_screen.dart new file mode 100644 index 0000000..ab7eba7 --- /dev/null +++ b/undomain/lib/pages/home/home_screen.dart @@ -0,0 +1,228 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:material_floating_search_bar_2/material_floating_search_bar_2.dart'; +import 'package:undomain/models/user/user_model.dart'; +import 'package:undomain/provider/user_provider.dart'; +import 'package:undomain/services/userservices/userservices.dart'; +import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/global/global_function.dart'; +import 'package:undomain/util/textstyles/text_styles.dart'; +import 'package:undomain/widgets/userListviwe/user_listviwe.dart'; + +class HomeScreen extends ConsumerStatefulWidget { + final bool isRestart; + const HomeScreen({super.key, required this.isRestart}); + + @override + ConsumerState createState() => _HomeScreenState(); +} + +class _HomeScreenState extends ConsumerState { + final FloatingSearchBarController _floatingSearchBarController = + FloatingSearchBarController(); + final Userservices _userservices = Userservices(); + final GlobalFunction _globalFunction = GlobalFunction(); + late Map user; + Uint8List? imagebytes; + String username = ""; + List searchedUsers = []; + + Future _searchUser(String query) async { + if (query.isEmpty) { + return; + } + Map response = await _userservices.getUserByUserName( + query, + ); + if (!response["success"]) { + print(response["massage"]); + _globalFunction.snackBarMassage(context, response["massage"], 3); + } else { + setState(() { + searchedUsers = response["users"]; + }); + } + } + + bool _hasShownError = false; + @override + Widget build(BuildContext context) { + final currentUserData = ref.watch(currentUserProvider); + double deviceW = MediaQuery.of(context).size.width; + double deviceH = MediaQuery.of(context).size.height; + double space = (deviceW - 72) / 2; + return SafeArea( + child: Scaffold( + body: currentUserData.when( + loading: + () => Center( + child: CircularProgressIndicator(color: utilPrimaryRed), + ), + + error: + (error, stackTrace) => + Center(child: Text('Error: ${error.toString()}')), + data: (currentuser) { + if ((!currentuser["success"] && !_hasShownError) || + currentuser["user"] == null) { + _hasShownError = true; + WidgetsBinding.instance.addPostFrameCallback((_) { + _globalFunction.snackBarMassage( + context, + currentuser["massage"], + 3, + ); + }); + } + if (currentuser["user"] == null) { + Center(child: CircularProgressIndicator(color: utilPrimaryRed)); + } + UserModel user = currentuser["user"]; + String base64String = user.profileUrl; + imagebytes = base64Decode(base64String); + return Column( + children: [ + Container( + width: double.infinity, + height: deviceH * 0.4, + child: Stack( + //fit: StackFit.expand, + children: [ + //background image + Image.asset( + "assets/mess.jpeg", + fit: BoxFit.fill, + height: deviceH * 0.4, + width: double.infinity, + ), + //user name + Positioned( + top: deviceH * 0.03, + left: deviceW * 0.03, + child: Chip( + label: RichText( + text: TextSpan( + children: [ + TextSpan(text: "Welcome ", style: textLabelRed), + TextSpan( + text: user.username ?? username, + style: textLabel, + ), + ], + ), + ), + autofocus: true, + backgroundColor: utilPrimaryWhite, + labelPadding: EdgeInsets.all(2), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + ), + ), + + //uaer profile picture + Positioned( + top: deviceH * 0.03, + right: deviceW * 0.03, + child: + imagebytes == null + ? CircleAvatar( + backgroundColor: utilPrimaryGrey, + radius: 24, + ) + : CircleAvatar( + backgroundColor: utilPrimaryGrey, + radius: 24, + backgroundImage: MemoryImage(imagebytes!), + ), + ), + //search bar + Positioned( + child: Padding( + padding: EdgeInsets.only(top: deviceH * 0.3), + child: searchBar(context), + ), + ), + ], + ), + ), + SizedBox(height: 16), + + //show all users(will avalible workers) + Expanded(child: UserListviwe(searchUsers: searchedUsers)), + ], + ); + }, + ), + ), + ); + } + + Widget searchBar(BuildContext context) { + final isPortrait = + MediaQuery.of(context).orientation == Orientation.portrait; + + return FloatingSearchBar( + hint: "Who you are looking for?", + controller: _floatingSearchBarController, + hintStyle: GoogleFonts.poppins( + color: utilPrimaryGrey, + fontSize: 11, + fontWeight: FontWeight.w500, + ), + scrollPadding: EdgeInsets.all(8), + transitionDuration: Duration(microseconds: 600), + transitionCurve: Curves.easeInOut, + autocorrect: true, + + borderRadius: BorderRadius.circular(24), + textInputAction: TextInputAction.search, + elevation: 2, + automaticallyImplyBackButton: false, + iconColor: utilPrimaryBlack, + leadingActions: [Icon(Icons.search, color: utilPrimaryGrey)], + physics: BouncingScrollPhysics(), + openAxisAlignment: 0, + width: isPortrait ? 500 : 750, + debounceDelay: Duration(microseconds: 400), + //serch + onSubmitted: (query) async { + searchedUsers = []; + await _searchUser(query); + }, + onQueryChanged: (query) {}, + transition: CircularFloatingSearchBarTransition(), + + actions: [], + builder: (context, transition) { + return ClipRRect( + borderRadius: BorderRadius.circular(24), + child: Material(color: utilPrimaryWhite, elevation: 1), + ); + }, + ); + } +} +// UserModel( +// contact: 0, +// referenceUrl: "", +// joinedDate: DateTime.now(), +// updatedDate: DateTime.now(), +// bio: "", +// followers: [], +// following: [], +// serviceDiscription: "", +// profileUrl: "", +// id: "", +// username: "unknown", +// password: "1234", +// email: "unknow@gmail.com", +// isCreator: false, +// isVerified: true, +// verifyCode: "", +// codeExpireTime: 1234, +// ); \ No newline at end of file diff --git a/undomain/lib/pages/home/homepage.dart b/undomain/lib/pages/home/homepage.dart deleted file mode 100644 index e14ca6c..0000000 --- a/undomain/lib/pages/home/homepage.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:flutter/material.dart'; - -class Homepage extends StatefulWidget { - const Homepage({super.key}); - - @override - State createState() => _HomepageState(); -} - -class _HomepageState extends State { - @override - Widget build(BuildContext context) { - return Scaffold(body: Column(children: [Text("Welcome to Homepage")])); - } -} diff --git a/undomain/lib/pages/home/main_screen.dart b/undomain/lib/pages/home/main_screen.dart new file mode 100644 index 0000000..4db1b72 --- /dev/null +++ b/undomain/lib/pages/home/main_screen.dart @@ -0,0 +1,131 @@ +import 'package:flutter/material.dart'; +import 'package:persistent_bottom_nav_bar/persistent_bottom_nav_bar.dart'; +import 'package:undomain/pages/home/home_screen.dart'; +import 'package:undomain/pages/profile/profile_scren.dart'; +import 'package:undomain/pages/reels/reel_screen.dart'; +import 'package:undomain/pages/streaming/streaming_screen.dart'; +import 'package:undomain/pages/update/update_screen.dart'; +import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/textstyles/text_styles.dart'; + +class Homepage extends StatefulWidget { + final bool isFromLogin; + final int index; + + const Homepage({ + super.key, + required this.isFromLogin, + required this.index, + + + }); + + @override + State createState() => _HomepageState(); +} + +class _HomepageState extends State { + late PersistentTabController _tabController; + + //renderd screens + List _buildScreen() { + return [ + HomeScreen(isRestart: widget.isFromLogin), + ReelScreen(), + StreamingScreen(), + UpdateScreen(), + ProfileScren(), + ]; + } + + + + //nav bar items + List _navBarItems() { + return [ + PersistentBottomNavBarItem( + icon: Icon(Icons.home_outlined), + title: "Home", + activeColorPrimary: utilPrimaryRed, + inactiveColorPrimary: utilPrimaryGrey, + ), + PersistentBottomNavBarItem( + icon: Icon(Icons.camera), + title: "Reels", + activeColorPrimary: utilPrimaryRed, + inactiveColorPrimary: utilPrimaryGrey, + ), + PersistentBottomNavBarItem( + icon: Icon(Icons.live_tv), + title: "Live", + activeColorPrimary: utilPrimaryRed, + inactiveColorPrimary: utilPrimaryGrey, + ), + PersistentBottomNavBarItem( + icon: Icon(Icons.update), + title: "Upgrade", + activeColorPrimary: utilPrimaryRed, + inactiveColorPrimary: utilPrimaryGrey, + ), + PersistentBottomNavBarItem( + icon: Icon(Icons.person_2_outlined), + title: "Profile", + textStyle: textLabel, + + activeColorPrimary: utilPrimaryRed, + inactiveColorPrimary: utilPrimaryGrey, + ), + ]; + } + + @override + void initState() { + _tabController = PersistentTabController(initialIndex: widget.index); + //_restart(); + super.initState(); + } + + + @override + Widget build(BuildContext context) { + return PersistentTabView( + context, + screens: _buildScreen(), + controller: _tabController, + items: _navBarItems(), + confineToSafeArea: true, + + handleAndroidBackButtonPress: true, + resizeToAvoidBottomInset: true, + stateManagement: true, + hideNavigationBarWhenKeyboardAppears: true, + margin: EdgeInsets.symmetric(horizontal: 8, vertical: 8), + decoration: NavBarDecoration( + borderRadius: BorderRadius.circular(24), + colorBehindNavBar: utilPrimaryWhite, + boxShadow: [ + BoxShadow( + color: utilPrimaryGrey.withOpacity(0.5), + offset: Offset(0, 0.5), + spreadRadius: 0, + blurRadius: 1, + ), + ], + ), + popBehaviorOnSelectedNavBarItemPress: PopBehavior.all, + animationSettings: NavBarAnimationSettings( + navBarItemAnimation: ItemAnimationSettings( + duration: Duration(milliseconds: 400), + curve: Curves.ease, + ), + screenTransitionAnimation: ScreenTransitionAnimationSettings( + animateTabTransition: true, + curve: Curves.ease, + duration: Duration(milliseconds: 200), + screenTransitionAnimationType: ScreenTransitionAnimationType.fadeIn, + ), + ), + // navBarStyle: NavBarStyle.style10, + ); + } +} diff --git a/undomain/lib/pages/profile/profile_scren.dart b/undomain/lib/pages/profile/profile_scren.dart new file mode 100644 index 0000000..567124d --- /dev/null +++ b/undomain/lib/pages/profile/profile_scren.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import 'package:undomain/router/router_names.dart'; +import 'package:undomain/services/auth_services/authservices.dart'; +import 'package:undomain/util/global/global_varibles.dart'; +import 'package:undomain/util/textstyles/text_styles.dart'; + +class ProfileScren extends ConsumerStatefulWidget { + const ProfileScren({super.key}); + + @override + ConsumerState createState() => _ProfileScrenState(); +} + +class _ProfileScrenState extends ConsumerState { + void _logout(WidgetRef ref) { + Authservices().logout(ref); + GoRouter.of(context).goNamed(RouterNames.loginPage); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: mainPagePaddingH, + vertical: mainPagePaddingV, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () { + _logout(ref); + }, + child: Text("Logout", style: textBody), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/undomain/lib/pages/reels/reel_screen.dart b/undomain/lib/pages/reels/reel_screen.dart new file mode 100644 index 0000000..da4baf0 --- /dev/null +++ b/undomain/lib/pages/reels/reel_screen.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class ReelScreen extends StatelessWidget { + const ReelScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold(); + } +} \ No newline at end of file diff --git a/undomain/lib/pages/restart/restart.dart b/undomain/lib/pages/restart/restart.dart new file mode 100644 index 0000000..2ac55a5 --- /dev/null +++ b/undomain/lib/pages/restart/restart.dart @@ -0,0 +1,30 @@ +import 'package:flutter/widgets.dart'; + +class RestartWidget extends StatefulWidget { + final Widget child; + const RestartWidget({Key? key, required this.child}) : super(key: key); + + static void restartApp(BuildContext context) { + final _RestartWidgetState? state = + context.findAncestorStateOfType<_RestartWidgetState>(); + state?.restartApp(); + } + + @override + State createState() => _RestartWidgetState(); +} + +class _RestartWidgetState extends State { + Key _key = UniqueKey(); + + void restartApp() { + setState(() { + _key = UniqueKey(); //trigger rebuild of the whole subtree + }); + } + + @override + Widget build(BuildContext context) { + return KeyedSubtree(key: _key, child: widget.child); + } +} diff --git a/undomain/lib/pages/streaming/live_screen.dart b/undomain/lib/pages/streaming/live_screen.dart new file mode 100644 index 0000000..d1f6b77 --- /dev/null +++ b/undomain/lib/pages/streaming/live_screen.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import 'package:undomain/models/user/user_model.dart'; +import 'package:undomain/provider/user_provider.dart'; +import 'package:undomain/router/router_names.dart'; +import 'package:undomain/secrets/secrets.dart'; +import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/global/global_function.dart'; +import 'package:undomain/widgets/avater/streaming_avater.dart'; +import 'package:zego_uikit_prebuilt_live_streaming/zego_uikit_prebuilt_live_streaming.dart'; + +class ZegoLiveScreen extends ConsumerStatefulWidget { + final bool isHost; + final String liveId; + const ZegoLiveScreen({super.key, required this.isHost, required this.liveId}); + + @override + ConsumerState createState() => _ZegoLiveScreenState(); +} + +class _ZegoLiveScreenState extends ConsumerState { + bool _hasShownError = false; + final GlobalFunction _globalFunction = GlobalFunction(); + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + ZegoUIKit().leaveRoom(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final getCurrentUser = ref.watch(currentUserProvider); + + return SafeArea( + child: getCurrentUser.when( + loading: + () => + Center(child: CircularProgressIndicator(color: utilPrimaryRed)), + + error: + (error, stackTrace) => + Center(child: Text('Error: ${error.toString()}')), + data: (currentuser) { + if ((!currentuser["success"] && !_hasShownError) || + currentuser["user"] == null) { + _hasShownError = true; + WidgetsBinding.instance.addPostFrameCallback((_) { + _globalFunction.snackBarMassage( + context, + currentuser["massage"], + 3, + ); + }); + } + if (currentuser["user"] == null) { + Center(child: CircularProgressIndicator(color: utilPrimaryRed)); + } + UserModel user = currentuser["user"]; + return ZegoUIKitPrebuiltLiveStreaming( + appID: Secrets().ZEGO_APPID, + appSign: Secrets().ZEGO_APPSING, + userID: user.id, + userName: user.username, + liveID: widget.liveId, + //when end the streaming + events: ZegoUIKitPrebuiltLiveStreamingEvents( + onEnded: (event, defaultAction) { + if (event.reason == ZegoLiveStreamingEndReason.hostEnd) { + GoRouter.of( + context, + ).goNamed(RouterNames.StremingConfigScreen); + } + if (event.reason == ZegoLiveStreamingEndReason.localLeave) { + GoRouter.of( + context, + ).goNamed(RouterNames.StremingConfigScreen); + } else { + GoRouter.of( + context, + ).goNamed(RouterNames.StremingConfigScreen); + } + }, + ), + config: + (widget.isHost + ? ZegoUIKitPrebuiltLiveStreamingConfig.host() + : ZegoUIKitPrebuiltLiveStreamingConfig.audience()) + ..avatarBuilder = customAvatarBuilder, + ); + }, + ), + ); + } +} diff --git a/undomain/lib/pages/streaming/log_streaming.dart b/undomain/lib/pages/streaming/log_streaming.dart new file mode 100644 index 0000000..8dc66f4 --- /dev/null +++ b/undomain/lib/pages/streaming/log_streaming.dart @@ -0,0 +1,132 @@ +import 'dart:math' as math; + +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:undomain/router/router_names.dart'; +import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/global/global_varibles.dart'; +import 'package:undomain/util/textstyles/text_styles.dart'; +import 'package:undomain/widgets/buttons/icon_button.dart'; +import 'package:undomain/widgets/expansionTitle/expansion_title.dart'; +import 'package:undomain/widgets/textboxes/authtext_box.dart'; + +class LogStreaming extends StatefulWidget { + const LogStreaming({super.key}); + + @override + State createState() => _LogStreamingState(); +} + +class _LogStreamingState extends State { + final TextEditingController _controller = TextEditingController(); + + String? selectedOption = "Comments"; +//additional settings + final List options = [ + "Comments", + "Distribution setting", + "Streaming filters", + "History", + ]; +//nav to streaming page + void _gotoLivePage( + BuildContext context, { + required bool isHost, + required String liveId, + }) { + GoRouter.of(context).goNamed( + RouterNames.zegoLiveScreen, + extra: {"isHost": isHost, "liveId": liveId}, + ); + } + + final String localUserID = math.Random().nextInt(10000).toString(); + @override + Widget build(BuildContext context) { + final deviceHeight = MediaQuery.of(context).size.height; + return Scaffold( + appBar: AppBar( + leading: IconButton( + onPressed: () { + GoRouter.of(context).goNamed( + RouterNames.mainpage, + extra: {"isFromLogin": false, "index": 2}, + ); + }, + icon: Icon(Icons.arrow_back_outlined), + iconSize: 24, + color: utilPrimaryBlack, + ), + ), + body: SingleChildScrollView( + keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag, + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: mainPagePaddingH, + vertical: mainPagePaddingV, + ), + child: Column( + children: [ + Align( + alignment: Alignment.center, + child: Text( + "Enter your liveID to start new streaming or you can join existing one adding shared liveID.", + style: textHint.copyWith(fontSize: 12), + textAlign: TextAlign.center, + ), + ), + RichText( + text: TextSpan( + children: [ + TextSpan(text: "Live_ID:", style: textLabelRed), + TextSpan(text: localUserID, style: textLabel), + ], + ), + ), + SizedBox(height: deviceHeight * 0.035), + AuthtextBox( + onSubmit: (p0) {}, + controller: _controller, + hint: "Enter Live ID", + isShow: false, + textInputAction: TextInputAction.done, + textInputType: TextInputType.number, + isValid: true, + ), + SizedBox(height: deviceHeight * 0.02), + //go live button + GestureDetector( + onTap: () { + // Prevent multiple instances when minimized + + _gotoLivePage( + context, + isHost: + _controller.text.trim() == localUserID ? true : false, + liveId: _controller.text.trim(), + ); + }, + child: IconTextButton(), + ), + //free space + SizedBox(height: deviceHeight * 0.15), + //addtionl setting drop down + Align( + alignment: Alignment.topLeft, + child: Text( + "additinal setting", + style: textLabelRed, + textAlign: TextAlign.left, + ), + ), + ExpansionTitleWidget(title: "Comments"), + ExpansionTitleWidget(title: "Distribution setting"), + ExpansionTitleWidget(title: "Streaming filters"), + ExpansionTitleWidget(title: "History"), + ], + ), + ), + ), + ); + } +} diff --git a/undomain/lib/pages/streaming/streaming_screen.dart b/undomain/lib/pages/streaming/streaming_screen.dart new file mode 100644 index 0000000..a2d8d40 --- /dev/null +++ b/undomain/lib/pages/streaming/streaming_screen.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:go_router/go_router.dart'; +import 'package:undomain/router/router_names.dart'; +import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/global/global_varibles.dart'; +import 'package:undomain/util/textstyles/text_styles.dart'; + +class StreamingScreen extends StatelessWidget { + const StreamingScreen({super.key}); + + @override + Widget build(BuildContext context) { + final buttonStyle = ElevatedButton.styleFrom( + backgroundColor: utilPrimaryRed, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + padding: EdgeInsets.symmetric(horizontal: mainPagePaddingH, vertical: 8), + ); + return Scaffold( + body: Padding( + padding: EdgeInsets.symmetric( + horizontal: mainPagePaddingH, + vertical: + mainPagePaddingV + MediaQuery.of(context).size.height * 0.05, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + //title + Center(child: SvgPicture.asset("assets/livetext.svg")), + //illustrator + SvgPicture.asset("assets/guitar.svg"), + //nav to config page + ElevatedButton( + style: buttonStyle, + onPressed: () { + GoRouter.of(context).goNamed(RouterNames.StremingConfigScreen); + }, + child: Text( + "start streaming", + style: textTitalSmall.copyWith(color: utilPrimaryWhite), + ), + ), + ], + ), + ), + ); + } +} diff --git a/undomain/lib/pages/update/update_screen.dart b/undomain/lib/pages/update/update_screen.dart new file mode 100644 index 0000000..59d446c --- /dev/null +++ b/undomain/lib/pages/update/update_screen.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class UpdateScreen extends StatelessWidget { + const UpdateScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold(); + } +} diff --git a/undomain/lib/provider/user_provider.dart b/undomain/lib/provider/user_provider.dart new file mode 100644 index 0000000..352533c --- /dev/null +++ b/undomain/lib/provider/user_provider.dart @@ -0,0 +1,15 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:undomain/services/userservices/userservices.dart'; + +//provider for fetched currently loged in users +final currentUserProvider = FutureProvider>((ref) async { + return await Userservices().getCurrentUser(); +}); + +//provider for fetched all other users +final allUserProvider = FutureProvider>((ref) async { + return await Userservices().getAllUser(); +}); +// final clearUserProvider = FutureProvider((ref) async { +// return await currentUserProvider. +// }); diff --git a/undomain/lib/router/go_router.dart b/undomain/lib/router/go_router.dart index 9fcc157..f201993 100644 --- a/undomain/lib/router/go_router.dart +++ b/undomain/lib/router/go_router.dart @@ -3,17 +3,22 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:undomain/pages/authentication/email_verification/email_verification.dart'; +import 'package:undomain/pages/authentication/fogotpassword/fogot_password.dart'; import 'package:undomain/pages/authentication/login/login_screen.dart'; import 'package:undomain/pages/authentication/register/register_screen.dart'; import 'package:undomain/pages/authentication/spalshscreen/spalsh.dart'; import 'package:undomain/pages/authentication/terms&conditions/terms_and_conditions.dart'; import 'package:undomain/pages/error/error_page.dart'; -import 'package:undomain/pages/home/homepage.dart'; +import 'package:undomain/pages/home/home_screen.dart'; +import 'package:undomain/pages/home/main_screen.dart'; +import 'package:undomain/pages/streaming/live_screen.dart'; +import 'package:undomain/pages/streaming/log_streaming.dart'; +import 'package:undomain/pages/streaming/streaming_screen.dart'; import 'package:undomain/router/router_names.dart'; class Routes { final goRouter = GoRouter( - initialLocation: "/verify", + initialLocation: "/", errorPageBuilder: (context, state) { return const MaterialPage(child: ErrorPage()); }, @@ -42,7 +47,7 @@ class Routes { return const TermsAndConditions(); }, ), - // //registerpage + //registerpage GoRoute( path: "/register", name: RouterNames.registerPage, @@ -55,7 +60,15 @@ class Routes { path: "/verify", name: RouterNames.verificationPage, builder: (context, state) { - return EmailVerification(); + final String userId = (state.extra as Map)["userId"]; + final bool isFromRegister = + (state.extra as Map)["isFromRegister"]; + final String email = (state.extra as Map)["email"]; + return EmailVerification( + userid: userId, + isForRegister: isFromRegister, + email: email, + ); }, ), //Homepage @@ -63,7 +76,67 @@ class Routes { path: "/home", name: RouterNames.homePage, builder: (context, state) { - return Homepage(); + bool isRestarted = (state.extra as Map)["start"]; + + return HomeScreen( + isRestart: isRestarted, + + ); + }, + ), + //Homepage + GoRoute( + path: "/fogotpassword", + name: RouterNames.fogotpasswordScreen, + builder: (context, state) { + return FogotPassword(); + }, + ), + //wrapper page + GoRoute( + path: "/wrapper", + name: RouterNames.wrapperScreen, + builder: (context, state) { + return WrapperScreen(); + }, + ), + //main screen + GoRoute( + path: "/main", + name: RouterNames.mainpage, + builder: (context, state) { + bool isFromLogin = + (state.extra as Map)["isFromLogin"]; + int index = + (state.extra as Map)["index"]; + return Homepage(isFromLogin: isFromLogin,index: index,); + }, + ), + //stream logpage + GoRoute( + path: "/stream", + name: RouterNames.StremingConfigScreen, + builder: (context, state) { + + return LogStreaming(); + }, + ), + //zego live stream page + GoRoute( + path: "/live", + name: RouterNames.zegoLiveScreen, + builder: (context, state) { + bool isHost = (state.extra as Map)["isHost"]; + String liveId = (state.extra as Map)["liveId"]; + return ZegoLiveScreen(isHost: isHost, liveId: liveId); + }, + ), + //llive first look page + GoRoute( + path: "/livestream", + name: RouterNames.mainStremaingPage, + builder: (context, state) { + return StreamingScreen(); }, ), ], diff --git a/undomain/lib/router/router_names.dart b/undomain/lib/router/router_names.dart index 56106b0..f6d69ec 100644 --- a/undomain/lib/router/router_names.dart +++ b/undomain/lib/router/router_names.dart @@ -1,8 +1,14 @@ class RouterNames { - static const String loginPage = "login"; - static const String registerPage = "register"; - static const String verificationPage = "verify"; - static const String homePage = "home"; + static const String loginPage = "/login"; + static const String registerPage = "/register"; + static const String verificationPage = "/verify"; + static const String homePage = "/home"; + static const String mainpage = "/main"; static const String termsAndConditions = "/terms"; static const String splashScreen = "/"; + static const String fogotpasswordScreen = "/fogotpassword"; + static const String wrapperScreen = "/wrapper"; + static const String StremingConfigScreen = "/stream"; + static const String zegoLiveScreen = "/live"; + static const String mainStremaingPage = "/livestream"; } diff --git a/undomain/lib/secrets/secrets.dart b/undomain/lib/secrets/secrets.dart new file mode 100644 index 0000000..8be42f7 --- /dev/null +++ b/undomain/lib/secrets/secrets.dart @@ -0,0 +1,5 @@ +class Secrets { + int ZEGO_APPID = 28439340; + String ZEGO_APPSING = + "fa42963266224d38a78401e3266172c17468fdf478797b1d5cda2aadc52ff90d"; +} diff --git a/undomain/lib/services/auth_services/authservices.dart b/undomain/lib/services/auth_services/authservices.dart new file mode 100644 index 0000000..5393b8d --- /dev/null +++ b/undomain/lib/services/auth_services/authservices.dart @@ -0,0 +1,165 @@ +import "dart:convert"; +import "dart:io"; + +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:http/http.dart" as http; +import "package:shared_preferences/shared_preferences.dart"; +import "package:undomain/provider/user_provider.dart"; + +class Authservices { + final baseUrl = "http://192.168.12.148:5000/api/auth"; + //register new user + Future> register( + File profileUrl, { + required String username, + required String email, + required String password, + }) async { + try { + final uri = Uri.parse("$baseUrl/register"); + //get response + final request = http.MultipartRequest('POST', uri); + //attach text fields + request.fields['username'] = username; + request.fields['email'] = email; + request.fields['password'] = password; + //attach file + request.files.add( + await http.MultipartFile.fromPath("profileUrl", profileUrl.path), + ); + //send request + final streamedResponse = await request.send(); + final response = await http.Response.fromStream(streamedResponse); + + //get body + final user = jsonDecode(response.body); + if (response.statusCode == 400 || response.statusCode == 500) { + return user; + } + + //store tooken in shared preferences + final SharedPreferences preferences = + await SharedPreferences.getInstance(); + //set jwt token + preferences.setString("token", user["newToken"]); + //set user id + preferences.setString("user", user["user"]["id"]); + print(user["newToken"]); + return user; + } catch (err) { + print("client side error $err"); + return {"succss": false, "massage": "Unexpected error"}; + } + } + + //verify new user + Future> verifyNewUser({ + required String userId, + required String verifyCode, + }) async { + try { + final response = await http.post( + Uri.parse("$baseUrl/verify"), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({"userId": userId, "verifyCode": verifyCode}), + ); + final user = jsonDecode(response.body); + if (response.statusCode == 400 || + response.statusCode == 408 || + response.statusCode == 500) { + return user; + } + return user; + } catch (err) { + print("client side error $err"); + return {"success": false, "massage": "Unexpected error"}; + } + } + + //login existing user + Future> login({ + required String username, + required String password, + }) async { + try { + final response = await http.post( + Uri.parse("$baseUrl/login"), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({"username": username, "password": password}), + ); + + final user = jsonDecode(response.body); + if (response.statusCode == 400 || response.statusCode == 500) { + return user; + } + //store tooken in shared preferences + final SharedPreferences preferences = + await SharedPreferences.getInstance(); + //save jwt + await preferences.setString("token", user["newToken"]); + //save user id + await preferences.setString("user", user["user"]["id"]); + print(user["newToken"]); + return user; + } catch (err) { + print("client side error $err"); + return {"success": false, "massage": "Unexpected error"}; + } + } + + //send reset password request with email and new password + Future> sendPasswordResetRequest({ + required String email, + }) async { + try { + final response = await http.post( + Uri.parse("$baseUrl/user-verification"), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({"email": email}), + ); + + final user = jsonDecode(response.body); + if (response.statusCode == 404 || response.statusCode == 500) { + return user; + } + + return user; + } catch (err) { + print("client side error $err"); + return {"success": false, "massage": "Unexpected error"}; + } + } + + //verify resset password + Future> verifyResetPassword({ + required String email, + required String otp, + required String password, + }) async { + try { + final response = await http.post( + Uri.parse("$baseUrl/reset-password"), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({"email": email, "otp": otp, "password": password}), + ); + + final user = jsonDecode(response.body); + if (response.statusCode == 404 || + response.statusCode == 500 || + response.statusCode == 400 || + response.statusCode == 408) { + return user; + } + return user; + } catch (err) { + return {"success": false, "massage": "Unexpected error"}; + } + } +//log out + Future logout(WidgetRef ref) async { + final SharedPreferences _pref = await SharedPreferences.getInstance(); + _pref.remove("token"); + ref.invalidate(currentUserProvider); + ref.invalidate(allUserProvider); + } +} diff --git a/undomain/lib/services/userservices/userservices.dart b/undomain/lib/services/userservices/userservices.dart new file mode 100644 index 0000000..0fe4e18 --- /dev/null +++ b/undomain/lib/services/userservices/userservices.dart @@ -0,0 +1,109 @@ +import "dart:convert"; + +import "package:http/http.dart" as http; +import "package:shared_preferences/shared_preferences.dart"; +import "package:undomain/models/user/user_model.dart"; + +class Userservices { + final baseUrl = "http://192.168.12.148:5000/api/user"; + //get jwt token + Future getToken() async { + final pref = await SharedPreferences.getInstance(); + return pref.getString("token"); + } + + //get userid + Future getUserId() async { + final pref = await SharedPreferences.getInstance(); + return pref.getString("user"); + } + + //get current device user details + Future> getCurrentUser() async { + try { + final token = await getToken(); + if (token == null) { + print("token not valid"); + return {"success": false, "massage": "Authenticated token not found"}; + } + final response = await http.get( + Uri.parse("$baseUrl/getcurrentuser"), + + headers: {'Content-Type': 'application/json', 'Authorization': token}, + ); + final user = jsonDecode(response.body); + + print(user); + + if (response.statusCode == 401) { + print("user getting error $user"); + return user; + } + UserModel currentUser = UserModel.fromJson(user["user"]); + return {"success": true, "user": currentUser}; + } catch (err) { + print("client side error $err"); + return {"success": false, "massage": "Unexpected error"}; + } + } + + //get all user details(avalible working) + Future> getAllUser() async { + try { + final token = await getToken(); + if (token == null) { + return {"success": false, "massage": "Authenticated token not found"}; + } + final response = await http.get( + Uri.parse("$baseUrl/getalluser"), + + headers: {'Content-Type': 'application/json', 'Authorization': token}, + ); + + Map allUsersMap = jsonDecode(response.body); + + if (response.statusCode == 500) { + return allUsersMap; + } + List users = allUsersMap["users"]; + List allUsers = + users.map((item) => UserModel.fromJson(item)).toList(); + return {"success": true, "users": allUsers}; + } catch (err) { + print("client side error $err"); + return {"success": false, "massage": "Unexpected error"}; + } + } + + //get user by usernname + Future> getUserByUserName(String username) async { + try { + final token = await getToken(); + if (token == null) { + return {"success": false, "massage": "Authenticated token not found"}; + } + final response = await http.get( + Uri.parse("$baseUrl/getuserbyusername/$username"), + + headers: {'Content-Type': 'application/json', 'Authorization': token}, + ); + final users = jsonDecode(response.body); + if (response.statusCode == 404 || + response.statusCode == 500 || + response.statusCode == 400) { + print(users); + return users; + } + List allusers = users["users"]; + List fetchedUsers = + allusers.map((user) => UserModel.fromJson(user)).toList(); + // if (users["users"].length > 1) { + // return users["users"]; + // } + return {"success": true, "users": fetchedUsers}; + } catch (err) { + print("client side error $err"); + return {"success": false, "massage": "Unexpected error"}; + } + } +} diff --git a/undomain/lib/util/colors/colors.dart b/undomain/lib/util/colors/colors.dart index 254bb27..6bacd4a 100644 --- a/undomain/lib/util/colors/colors.dart +++ b/undomain/lib/util/colors/colors.dart @@ -5,3 +5,4 @@ final utilPrimaryRed = Color(0xffCD0000); final utilPrimaryWhite = Color(0xffEDECEC); final utilPrimaryBlack = Color(0xff1E1E1E); final utilPrimaryGrey = Color(0xff676767); +final utilNavBarColor = Color(0xff476810); diff --git a/undomain/lib/util/global/global_function.dart b/undomain/lib/util/global/global_function.dart new file mode 100644 index 0000000..de0c90e --- /dev/null +++ b/undomain/lib/util/global/global_function.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/global/global_varibles.dart'; +import 'package:undomain/util/textstyles/text_styles.dart'; + +class GlobalFunction { + void snackBarMassage(BuildContext context, String text, int duration) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: utilPrimaryRed, + closeIconColor: utilPrimaryWhite, + elevation: 1, + showCloseIcon: true, + duration: Duration(seconds: duration), + padding: EdgeInsets.symmetric(horizontal: authScreenPaddingH), + content: Text(text, style: textSnackbar), + ), + ); + } +} diff --git a/undomain/lib/util/global/global_varibles.dart b/undomain/lib/util/global/global_varibles.dart index 8f087a1..c88b1ac 100644 --- a/undomain/lib/util/global/global_varibles.dart +++ b/undomain/lib/util/global/global_varibles.dart @@ -1,3 +1,7 @@ const double authScreenPaddingH = 20; const double authScreenPaddingV = 40; const double authButtonRadius = 36; +const double mainPagePaddingH = 20; +const double mainPagePaddingV = 15; + +bool isInitialUser = true; diff --git a/undomain/lib/util/textstyles/text_styles.dart b/undomain/lib/util/textstyles/text_styles.dart index 8accaad..f4e7984 100644 --- a/undomain/lib/util/textstyles/text_styles.dart +++ b/undomain/lib/util/textstyles/text_styles.dart @@ -38,3 +38,8 @@ final textTitalSmall = GoogleFonts.poppins( fontSize: 16, fontWeight: FontWeight.w600, ); +final textSnackbar = GoogleFonts.poppins( + color: utilPrimaryWhite, + fontSize: 11, + fontWeight: FontWeight.w400, +); diff --git a/undomain/lib/widgets/avater/streaming_avater.dart b/undomain/lib/widgets/avater/streaming_avater.dart new file mode 100644 index 0000000..525302c --- /dev/null +++ b/undomain/lib/widgets/avater/streaming_avater.dart @@ -0,0 +1,32 @@ + +// Flutter imports: +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:zego_uikit_prebuilt_live_streaming/zego_uikit_prebuilt_live_streaming.dart'; + +Widget customAvatarBuilder( + BuildContext context, + Size size, + ZegoUIKitUser? user, + Map extraInfo, +) { + return CachedNetworkImage( + imageUrl: 'https://robohash.org/${user?.id}.png', + imageBuilder: (context, imageProvider) => Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: imageProvider, + fit: BoxFit.cover, + ), + ), + ), + progressIndicatorBuilder: (context, url, downloadProgress) => + CircularProgressIndicator(value: downloadProgress.progress), + errorWidget: (context, url, error) { + return ZegoAvatar(user: user, avatarSize: size); + }, + ); +} diff --git a/undomain/lib/widgets/buttons/authpage_button.dart b/undomain/lib/widgets/buttons/authpage_button.dart index 0a0bfb0..bdfe6e9 100644 --- a/undomain/lib/widgets/buttons/authpage_button.dart +++ b/undomain/lib/widgets/buttons/authpage_button.dart @@ -1,30 +1,32 @@ import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; import 'package:undomain/util/colors/colors.dart'; import 'package:undomain/util/global/global_varibles.dart'; import 'package:undomain/util/textstyles/text_styles.dart'; class AuthpageButton extends StatelessWidget { final String text; - - final String path; - const AuthpageButton({super.key, required this.text, required this.path}); + final bool isLoading; + const AuthpageButton({ + super.key, + required this.text, + required this.isLoading, + }); @override Widget build(BuildContext context) { - return GestureDetector( - onTap: () { - GoRouter.of(context).goNamed(path); - }, - child: Container( - width: double.infinity, - height: MediaQuery.of(context).size.height * 0.07, - child: Center(child: Text(text, style: textTitle)), + return Container( + width: double.infinity, + height: MediaQuery.of(context).size.height * 0.07, + child: Center( + child: + isLoading + ? CircularProgressIndicator(color: utilPrimaryWhite) + : Text(text, style: textTitle), + ), - decoration: BoxDecoration( - color: utilPrimaryRed, - borderRadius: BorderRadius.circular(authButtonRadius), - ), + decoration: BoxDecoration( + color: utilPrimaryRed, + borderRadius: BorderRadius.circular(authButtonRadius), ), ); } diff --git a/undomain/lib/widgets/buttons/icon_button.dart b/undomain/lib/widgets/buttons/icon_button.dart new file mode 100644 index 0000000..61a9a69 --- /dev/null +++ b/undomain/lib/widgets/buttons/icon_button.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/textstyles/text_styles.dart'; + +class IconTextButton extends StatelessWidget { + const IconTextButton({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.symmetric(vertical: 8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: utilPrimaryRed, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + //icon + Icon(Icons.live_tv, color: utilPrimaryWhite, size: 24), + //text + Text("Make Fun", style: textTitle), + ], + ), + ); + } +} diff --git a/undomain/lib/widgets/expansionTitle/expansion_title.dart b/undomain/lib/widgets/expansionTitle/expansion_title.dart new file mode 100644 index 0000000..a214037 --- /dev/null +++ b/undomain/lib/widgets/expansionTitle/expansion_title.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/textstyles/text_styles.dart'; + +class ExpansionTitleWidget extends StatelessWidget { + final String title; + const ExpansionTitleWidget({super.key, required this.title}); + + @override + Widget build(BuildContext context) { + return ExpansionTile( + title: Text(title, style: textBody), + expansionAnimationStyle: AnimationStyle( + duration: Duration(milliseconds: 500), + curve: Curves.easeInOut, + reverseCurve: Curves.easeInOut, + ), + + collapsedShape: Border.fromBorderSide(BorderSide.none), + + backgroundColor: utilPrimaryWhite, + iconColor: utilPrimaryBlack, + + children: [], + ); + } +} diff --git a/undomain/lib/widgets/textboxes/authtext_box.dart b/undomain/lib/widgets/textboxes/authtext_box.dart index a9c90e2..e4486d4 100644 --- a/undomain/lib/widgets/textboxes/authtext_box.dart +++ b/undomain/lib/widgets/textboxes/authtext_box.dart @@ -9,6 +9,8 @@ class AuthtextBox extends StatelessWidget { final bool isShow; final TextInputAction textInputAction; final TextInputType textInputType; + final String? Function(String?)? validChecker; + final bool isValid; const AuthtextBox({ super.key, required this.onSubmit, @@ -17,20 +19,24 @@ class AuthtextBox extends StatelessWidget { required this.isShow, required this.textInputAction, required this.textInputType, + this.validChecker, + required this.isValid, }); @override Widget build(BuildContext context) { return TextFormField( onFieldSubmitted: onSubmit, + validator: validChecker, controller: controller, textInputAction: textInputAction, keyboardType: textInputType, obscureText: isShow, cursorColor: utilPrimaryGrey, + decoration: InputDecoration( hintText: hint, - hintStyle: textHint, + hintStyle: isValid ? textHint : textLabelRed, contentPadding: EdgeInsets.symmetric( vertical: MediaQuery.of(context).size.height * 0.02, diff --git a/undomain/lib/widgets/userListviwe/user_listviwe.dart b/undomain/lib/widgets/userListviwe/user_listviwe.dart new file mode 100644 index 0000000..c6cd2da --- /dev/null +++ b/undomain/lib/widgets/userListviwe/user_listviwe.dart @@ -0,0 +1,115 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:undomain/models/user/user_model.dart'; +import 'package:undomain/provider/user_provider.dart'; +import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/global/global_function.dart'; +import 'package:undomain/util/textstyles/text_styles.dart'; + +class UserListviwe extends ConsumerWidget { + final List searchUsers; + UserListviwe({super.key, required this.searchUsers}); + //avalible worker list wive + final GlobalFunction _globalFunction = GlobalFunction(); + bool _hasShownError = false; + @override + Widget build(BuildContext context, WidgetRef ref) { + final allUserData = ref.watch(allUserProvider); + return allUserData.when( + error: + (error, stackTrace) => + Center(child: Text('Error: ${error.toString()}')), + loading: + () => Center(child: CircularProgressIndicator(color: utilPrimaryRed)), + data: (allusers) { + if (!allusers["success"] && !_hasShownError) { + _hasShownError = true; + WidgetsBinding.instance.addPostFrameCallback((_) { + print(allusers["massage"]); + _globalFunction.snackBarMassage(context, allusers["massage"], 3); + }); + } + if (searchUsers.isNotEmpty) { + return ListView.builder( + padding: EdgeInsets.all(8), + itemCount: searchUsers.length, + scrollDirection: Axis.vertical, + shrinkWrap: true, + physics: AlwaysScrollableScrollPhysics(), + + itemBuilder: (context, index) { + UserModel user = searchUsers[index]; + Uint8List userImage = base64Decode(user.profileUrl); + //user card + return Card( + elevation: 1, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + //user pic + child: ListTile( + contentPadding: EdgeInsets.all(8), + leading: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + ), + child: Image.memory(userImage), + ), + //username + title: Text(user.username, style: textBody), + //user contact + subtitle: Text(user.email, style: textLabel), + onTap: () { + //navigate to user profile + }, + ), + ); + }, + ); + } else { + List users = allusers["users"]; + return ListView.builder( + padding: EdgeInsets.all(8), + itemCount: users.length, + scrollDirection: Axis.vertical, + + shrinkWrap: true, + physics: AlwaysScrollableScrollPhysics(), + + itemBuilder: (context, index) { + UserModel user = users[index]; + Uint8List userImage = base64Decode(user.profileUrl); + //user card + return Card( + elevation: 1, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + //user pic + child: ListTile( + contentPadding: EdgeInsets.all(8), + leading: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + ), + child: Image.memory(userImage), + ), + //username + title: Text(user.username, style: textBody), + //user contact + subtitle: Text(user.email, style: textLabel), + onTap: () { + //navigate to user profile + }, + ), + ); + }, + ); + } + }, + ); + } +} diff --git a/undomain/linux/flutter/generated_plugin_registrant.cc b/undomain/linux/flutter/generated_plugin_registrant.cc index e71a16d..0cf475c 100644 --- a/undomain/linux/flutter/generated_plugin_registrant.cc +++ b/undomain/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,14 @@ #include "generated_plugin_registrant.h" +#include +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); + g_autoptr(FlPluginRegistrar) zego_express_engine_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "ZegoExpressEnginePlugin"); + zego_express_engine_plugin_register_with_registrar(zego_express_engine_registrar); } diff --git a/undomain/linux/flutter/generated_plugins.cmake b/undomain/linux/flutter/generated_plugins.cmake index 2e1de87..11ad07c 100644 --- a/undomain/linux/flutter/generated_plugins.cmake +++ b/undomain/linux/flutter/generated_plugins.cmake @@ -3,6 +3,8 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux + zego_express_engine ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/undomain/macos/Flutter/GeneratedPluginRegistrant.swift b/undomain/macos/Flutter/GeneratedPluginRegistrant.swift index e777c67..2774f15 100644 --- a/undomain/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/undomain/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,8 +5,28 @@ import FlutterMacOS import Foundation +import connectivity_plus +import device_info_plus +import file_picker +import file_selector_macos +import package_info_plus import path_provider_foundation +import shared_preferences_foundation +import sqflite_darwin +import wakelock_plus +import zego_express_engine +import zego_zim func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) + DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) + FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) + WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) + ZegoExpressEnginePlugin.register(with: registry.registrar(forPlugin: "ZegoExpressEnginePlugin")) + ZegoZimPlugin.register(with: registry.registrar(forPlugin: "ZegoZimPlugin")) } diff --git a/undomain/pubspec.lock b/undomain/pubspec.lock index 3a53c7d..1c8de25 100644 --- a/undomain/pubspec.lock +++ b/undomain/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + animated_splash_screen: + dependency: "direct main" + description: + name: animated_splash_screen + sha256: f45634db6ec4e8cf034c53e03f3bd83898a16fe3c9286bf5510b6831dfcf2124 + url: "https://pub.dev" + source: hosted + version: "1.3.0" ansicolor: dependency: transitive description: @@ -25,6 +33,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.7.0" + asn1lib: + dependency: transitive + description: + name: asn1lib + sha256: e02d018628c870ef2d7f03e33f9ad179d89ff6ec52ca6c56bcb80bcef979867f + url: "https://pub.dev" + source: hosted + version: "1.6.2" async: dependency: transitive description: @@ -41,6 +57,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" + url: "https://pub.dev" + source: hosted + version: "3.4.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" + url: "https://pub.dev" + source: hosted + version: "4.1.1" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" + url: "https://pub.dev" + source: hosted + version: "1.3.1" characters: dependency: transitive description: @@ -65,6 +105,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.1" + connectivity_plus: + dependency: transitive + description: + name: connectivity_plus + sha256: "04bf81bb0b77de31557b58d052b24b3eee33f09a6e7a8c68a3e247c7df19ec27" + url: "https://pub.dev" + source: hosted + version: "6.1.3" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + url: "https://pub.dev" + source: hosted + version: "0.3.4+2" crypto: dependency: transitive description: @@ -89,6 +161,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + dbus: + dependency: transitive + description: + name: dbus + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + url: "https://pub.dev" + source: hosted + version: "0.7.11" + device_info_plus: + dependency: transitive + description: + name: device_info_plus + sha256: "306b78788d1bb569edb7c55d622953c2414ca12445b41c9117963e03afc5c513" + url: "https://pub.dev" + source: hosted + version: "11.3.3" + device_info_plus_platform_interface: + dependency: transitive + description: + name: device_info_plus_platform_interface + sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2" + url: "https://pub.dev" + source: hosted + version: "7.0.2" + encrypt: + dependency: transitive + description: + name: encrypt + sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2" + url: "https://pub.dev" + source: hosted + version: "5.0.3" fake_async: dependency: transitive description: @@ -105,11 +209,83 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + file_picker: + dependency: transitive + description: + name: file_picker + sha256: ab13ae8ef5580a411c458d6207b6774a6c237d77ac37011b13994879f68a8810 + url: "https://pub.dev" + source: hosted + version: "8.3.7" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" + url: "https://pub.dev" + source: hosted + version: "0.9.3+2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "271ab9986df0c135d45c3cdb6bd0faa5db6f4976d3e4b437cf7d0f258d941bfc" + url: "https://pub.dev" + source: hosted + version: "0.9.4+2" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b" + url: "https://pub.dev" + source: hosted + version: "0.9.3+4" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + floating: + dependency: transitive + description: + name: floating + sha256: e51ce1dbcab3ea83da0ad1b07f2091b99c0e8680184c780a000567f41234d454 + url: "https://pub.dev" + source: hosted + version: "6.0.0" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" + url: "https://pub.dev" + source: hosted + version: "3.4.1" flutter_lints: dependency: "direct dev" description: @@ -118,6 +294,19 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.0" + flutter_localizations: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_logs: + dependency: transitive + description: + name: flutter_logs + sha256: "46880b3da87bf66d10c69505fd8dec1ef78fe1793fc909169ddb9aa9fe34f164" + url: "https://pub.dev" + source: hosted + version: "2.2.1" flutter_native_splash: dependency: "direct main" description: @@ -126,6 +315,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.6" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "5a1e6fb2c0561958d7e4c33574674bda7b77caaca7a33b758876956f2902eea3" + url: "https://pub.dev" + source: hosted + version: "2.0.27" + flutter_riverpod: + dependency: "direct main" + description: + name: flutter_riverpod + sha256: "9532ee6db4a943a1ed8383072a2e3eeda041db5657cdf6d2acecf3c21ecbe7e1" + url: "https://pub.dev" + source: hosted + version: "2.6.1" + flutter_styled_toast: + dependency: transitive + description: + name: flutter_styled_toast + sha256: e667f13a665820eb0fa8506547e47eacbcddf1948d6d3036cfd3b089bd4b0516 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: d44bf546b13025ec7353091516f6881f1d4c633993cb109c3916c3a0159dadf1 + url: "https://pub.dev" + source: hosted + version: "2.1.0" flutter_test: dependency: "direct dev" description: flutter @@ -161,7 +382,7 @@ packages: source: hosted version: "0.15.5+1" http: - dependency: transitive + dependency: "direct main" description: name: http sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f @@ -184,6 +405,86 @@ packages: url: "https://pub.dev" source: hosted version: "4.5.4" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "8bd392ba8b0c8957a157ae0dc9fcf48c58e6c20908d5880aea1d79734df090e9" + url: "https://pub.dev" + source: hosted + version: "0.8.12+22" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" + url: "https://pub.dev" + source: hosted + version: "0.8.12+2" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" + url: "https://pub.dev" + source: hosted + version: "2.10.1" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + intl: + dependency: transitive + description: + name: intl + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + url: "https://pub.dev" + source: hosted + version: "0.19.0" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" leak_tracker: dependency: transitive description: @@ -240,6 +541,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.11.1" + material_floating_search_bar_2: + dependency: "direct main" + description: + name: material_floating_search_bar_2 + sha256: ab0c6d209d9491f98dd4c72f2641d0ba1dd35c87effca1f23d8679bece43add0 + url: "https://pub.dev" + source: hosted + version: "0.5.0" meta: dependency: transitive description: @@ -248,6 +557,62 @@ packages: url: "https://pub.dev" source: hosted version: "1.16.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + native_device_orientation: + dependency: transitive + description: + name: native_device_orientation + sha256: "0c330c068575e4be72cce5968ca479a3f8d5d1e5dfce7d89d5c13a1e943b338c" + url: "https://pub.dev" + source: hosted + version: "2.0.3" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + package_info_plus: + dependency: transitive + description: + name: package_info_plus + sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" + url: "https://pub.dev" + source: hosted + version: "8.3.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + page_transition: + dependency: "direct main" + description: + name: page_transition + sha256: "9d2a780d7d68b53ae82fbcc43e06a16195e6775e9aae40e55dc0cbb593460f9d" + url: "https://pub.dev" + source: hosted + version: "2.2.1" path: dependency: transitive description: @@ -256,6 +621,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" path_provider: dependency: transitive description: @@ -304,6 +677,62 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + permission_handler: + dependency: transitive + description: + name: permission_handler + sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849" + url: "https://pub.dev" + source: hosted + version: "11.4.0" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc + url: "https://pub.dev" + source: hosted + version: "12.1.0" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 + url: "https://pub.dev" + source: hosted + version: "9.4.7" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" + url: "https://pub.dev" + source: hosted + version: "0.1.3+5" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 + url: "https://pub.dev" + source: hosted + version: "4.3.0" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + persistent_bottom_nav_bar: + dependency: "direct main" + description: + name: persistent_bottom_nav_bar + sha256: "6aa9b97ced1abd92c90cedd1997d34ea0b35c3ded762ac6063baccc299b0c4c5" + url: "https://pub.dev" + source: hosted + version: "6.2.1" petitparser: dependency: transitive description: @@ -336,6 +765,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" + url: "https://pub.dev" + source: hosted + version: "3.9.1" posix: dependency: transitive description: @@ -344,6 +781,78 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.1" + riverpod: + dependency: transitive + description: + name: riverpod + sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959" + url: "https://pub.dev" + source: hosted + version: "2.6.1" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.dev" + source: hosted + version: "0.28.0" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" + url: "https://pub.dev" + source: hosted + version: "2.5.3" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: c2c8c46297b5d6a80bed7741ec1f2759742c77d272f1a1698176ae828f8e1a18 + url: "https://pub.dev" + source: hosted + version: "2.4.9" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 + url: "https://pub.dev" + source: hosted + version: "2.4.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" sky_engine: dependency: transitive description: flutter @@ -357,6 +866,54 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.1" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: "2b3070c5fa881839f8b402ee4a39c1b4d561704d4ebbbcfb808a119bc2a1701b" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "84731e8bfd8303a3389903e01fb2141b6e59b5973cacbb0929021df08dddbe8b" + url: "https://pub.dev" + source: hosted + version: "2.5.5" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" + url: "https://pub.dev" + source: hosted + version: "2.4.0" stack_trace: dependency: transitive description: @@ -365,6 +922,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.12.1" + state_notifier: + dependency: transitive + description: + name: state_notifier + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb + url: "https://pub.dev" + source: hosted + version: "1.0.0" + statemachine: + dependency: transitive + description: + name: statemachine + sha256: "42ce52468879383c60d4983526114d91282b8b0c36657bc7d58be88975a02982" + url: "https://pub.dev" + source: hosted + version: "3.3.1" stream_channel: dependency: transitive description: @@ -381,6 +954,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "0669c70faae6270521ee4f05bffd2919892d42d1276e6c495be80174b6bc0ef6" + url: "https://pub.dev" + source: hosted + version: "3.3.1" term_glyph: dependency: transitive description: @@ -421,6 +1002,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + uuid: + dependency: transitive + description: + name: uuid + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff + url: "https://pub.dev" + source: hosted + version: "4.5.1" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "44cc7104ff32563122a929e4620cf3efd584194eec6d1d913eb5ba593dbcf6de" + url: "https://pub.dev" + source: hosted + version: "1.1.18" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" + url: "https://pub.dev" + source: hosted + version: "1.1.13" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad" + url: "https://pub.dev" + source: hosted + version: "1.1.16" vector_math: dependency: transitive description: @@ -429,6 +1042,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + visibility_detector: + dependency: transitive + description: + name: visibility_detector + sha256: dd5cc11e13494f432d15939c3aa8ae76844c42b723398643ce9addb88a5ed420 + url: "https://pub.dev" + source: hosted + version: "0.4.0+2" vm_service: dependency: transitive description: @@ -437,6 +1058,22 @@ packages: url: "https://pub.dev" source: hosted version: "14.3.1" + wakelock_plus: + dependency: transitive + description: + name: wakelock_plus + sha256: b6962cd9fc15e4843b573ba7b53bc46dd8a787594cf9ed5c5182581924656a58 + url: "https://pub.dev" + source: hosted + version: "1.3.1" + wakelock_plus_platform_interface: + dependency: transitive + description: + name: wakelock_plus_platform_interface + sha256: e10444072e50dbc4999d7316fd303f7ea53d31c824aa5eb05d7ccbdd98985207 + url: "https://pub.dev" + source: hosted + version: "1.2.3" web: dependency: transitive description: @@ -445,6 +1082,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + win32: + dependency: transitive + description: + name: win32 + sha256: dc6ecaa00a7c708e5b4d10ee7bec8c270e9276dfcab1783f57e9962d7884305f + url: "https://pub.dev" + source: hosted + version: "5.12.0" + win32_registry: + dependency: transitive + description: + name: win32_registry + sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" + url: "https://pub.dev" + source: hosted + version: "2.1.0" xdg_directories: dependency: transitive description: @@ -469,6 +1122,70 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.3" + zego_callkit: + dependency: transitive + description: + name: zego_callkit + sha256: "8954dcfaf94e5546fd2ebec6b0f0303dfd226d3a4c706336af6ea837011a8b37" + url: "https://pub.dev" + source: hosted + version: "1.0.0+5" + zego_express_engine: + dependency: transitive + description: + name: zego_express_engine + sha256: "2edd207f5299e5dcfa44c7b4e8d2088e718bab81d96bdc6b78a7649adaac1361" + url: "https://pub.dev" + source: hosted + version: "3.20.0" + zego_plugin_adapter: + dependency: transitive + description: + name: zego_plugin_adapter + sha256: af781427cf0f299f5b5760b1d0fe8147b64abac8a535d4130c6eedc166d26326 + url: "https://pub.dev" + source: hosted + version: "2.13.9" + zego_uikit: + dependency: "direct main" + description: + name: zego_uikit + sha256: f5640ee066290db176e1bf602032819206003336b47bf1c054d0149cb9e42764 + url: "https://pub.dev" + source: hosted + version: "2.28.12" + zego_uikit_prebuilt_live_streaming: + dependency: "direct main" + description: + name: zego_uikit_prebuilt_live_streaming + sha256: e15f7d4a4d7aa58a2969c1b71bd01771397cad71a84c1da767e654a57bad3d61 + url: "https://pub.dev" + source: hosted + version: "3.13.15" + zego_uikit_signaling_plugin: + dependency: "direct main" + description: + name: zego_uikit_signaling_plugin + sha256: "31a903d3bf1c22ea9281d6979c35446a3cc3ae54964855008b6395f0acc6c422" + url: "https://pub.dev" + source: hosted + version: "2.8.12" + zego_zim: + dependency: transitive + description: + name: zego_zim + sha256: "7149128e7666e568ba9f1d1dfd154f404e889995962c46f35c11a26562dde397" + url: "https://pub.dev" + source: hosted + version: "2.20.0+1" + zego_zpns: + dependency: transitive + description: + name: zego_zpns + sha256: "5aed712bfbf456a8da973ef5521ff614194ef3f127af96e885a62fa54c6c92a5" + url: "https://pub.dev" + source: hosted + version: "2.8.0" sdks: dart: ">=3.7.2 <4.0.0" flutter: ">=3.27.0" diff --git a/undomain/pubspec.yaml b/undomain/pubspec.yaml index c047d5d..4a00967 100644 --- a/undomain/pubspec.yaml +++ b/undomain/pubspec.yaml @@ -38,6 +38,20 @@ dependencies: go_router: ^14.8.1 pinput: ^5.0.1 flutter_native_splash: ^2.4.6 + animated_splash_screen: ^1.3.0 + page_transition: ^2.2.1 + image_picker: ^1.1.2 + http: ^1.3.0 + shared_preferences: ^2.5.3 + persistent_bottom_nav_bar: ^6.2.1 + material_floating_search_bar_2: ^0.5.0 + flutter_riverpod: ^2.6.1 + zego_uikit: ^2.28.12 + zego_uikit_prebuilt_live_streaming: ^3.13.15 + zego_uikit_signaling_plugin: ^2.8.12 + cached_network_image: ^3.4.1 + flutter_svg: ^2.1.0 + dev_dependencies: flutter_test: @@ -62,10 +76,9 @@ flutter: uses-material-design: true # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - + assets: + - assets/ + # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/to/resolution-aware-images diff --git a/undomain/windows/flutter/generated_plugin_registrant.cc b/undomain/windows/flutter/generated_plugin_registrant.cc index 8b6d468..ae55543 100644 --- a/undomain/windows/flutter/generated_plugin_registrant.cc +++ b/undomain/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,21 @@ #include "generated_plugin_registrant.h" +#include +#include +#include +#include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + ConnectivityPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); + PermissionHandlerWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); + ZegoExpressEnginePluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ZegoExpressEnginePlugin")); + ZegoZimPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ZegoZimPlugin")); } diff --git a/undomain/windows/flutter/generated_plugins.cmake b/undomain/windows/flutter/generated_plugins.cmake index b93c4c3..1c1935c 100644 --- a/undomain/windows/flutter/generated_plugins.cmake +++ b/undomain/windows/flutter/generated_plugins.cmake @@ -3,6 +3,11 @@ # list(APPEND FLUTTER_PLUGIN_LIST + connectivity_plus + file_selector_windows + permission_handler_windows + zego_express_engine + zego_zim ) list(APPEND FLUTTER_FFI_PLUGIN_LIST