├── lib ├── core │ ├── app │ │ ├── .gitkeep │ │ ├── colors │ │ │ └── .gitkeep │ │ ├── lang │ │ │ └── .gitkeep │ │ ├── themes │ │ │ ├── .gitkeep │ │ │ └── box_shadow.dart │ │ ├── constant │ │ │ ├── socket_events.dart │ │ │ ├── data_channel_events.dart │ │ │ ├── endpoints.dart │ │ │ ├── constants.dart │ │ │ └── storage_keys.dart │ │ ├── constants.dart │ │ ├── config │ │ │ └── base_local_data.dart │ │ └── application.dart │ ├── error │ │ ├── .gitkeep │ │ └── failure.dart │ ├── types │ │ ├── .gitkeep │ │ ├── service_method.dart │ │ └── http_status_code.dart │ ├── util │ │ ├── .gitkeep │ │ ├── styles │ │ │ ├── style.dart │ │ │ ├── auth_style.dart │ │ │ ├── home_style.dart │ │ │ ├── search_style.dart │ │ │ ├── chat_style.dart │ │ │ └── profile_style.dart │ │ ├── after_layout_mixin.dart │ │ ├── sizer_custom │ │ │ ├── sizer.dart │ │ │ ├── widget.dart │ │ │ ├── extension.dart │ │ │ └── util.dart │ │ ├── common │ │ │ ├── pull_to_refresh │ │ │ │ └── pull_to_refresh.dart │ │ │ └── touchable_opacity.dart │ │ ├── logger.dart │ │ ├── stop_watch_api.dart │ │ ├── dio_transformer.dart │ │ ├── custom_image │ │ │ ├── place_holder_image.dart │ │ │ └── default_image.dart │ │ ├── app_bars │ │ │ └── appbar_none.dart │ │ ├── numeral │ │ │ ├── parser.dart │ │ │ └── numeral.dart │ │ └── path_helper.dart │ ├── injection │ │ ├── .gitkeep │ │ └── injection_container.dart │ ├── navigator │ │ ├── .gitkeep │ │ ├── app_routes.dart │ │ ├── transition_route.dart │ │ └── app_navigator_observer.dart │ ├── network │ │ ├── .gitkeep │ │ └── url_launcher_helper.dart │ └── usecase │ │ ├── .gitkeep │ │ └── usecase.dart ├── features │ ├── chat │ │ ├── data │ │ │ └── .gitkeep │ │ ├── domain │ │ │ └── .gitkeep │ │ └── presentation │ │ │ └── widgets │ │ │ └── button_option_widget.dart │ ├── home │ │ ├── data │ │ │ ├── .gitkeep │ │ │ ├── datasources │ │ │ │ ├── remote_live_stream_source.dart │ │ │ │ └── local_live_stream_source.dart │ │ │ ├── repositories │ │ │ │ └── live_stream_repository_impl.dart │ │ │ └── model │ │ │ │ └── category_model.dart │ │ ├── domain │ │ │ ├── repositories │ │ │ │ └── live_stream_repository.dart │ │ │ └── usecases │ │ │ │ └── get_list_live_streaming.dart │ │ └── presentation │ │ │ ├── splash_screen.dart │ │ │ └── widgets │ │ │ ├── list_user_follow.dart │ │ │ ├── button_circle.dart │ │ │ ├── list_live_stream.dart │ │ │ ├── category_card.dart │ │ │ └── list_category_home.dart │ ├── search │ │ ├── data │ │ │ ├── .gitkeep │ │ │ └── top_search_model.dart │ │ ├── domain │ │ │ └── .gitkeep │ │ └── presentation │ │ │ └── widgets │ │ │ └── search_more_widget.dart │ ├── profile │ │ ├── data │ │ │ ├── .gitkeep │ │ │ └── list_live_card_model.dart │ │ ├── domain │ │ │ └── .gitkeep │ │ └── presentation │ │ │ └── widgets │ │ │ ├── index_info_user.dart │ │ │ ├── circle_icon.dart │ │ │ ├── gribview_live_card.dart │ │ │ ├── edit_profile_widget.dart │ │ │ ├── login_setting.dart │ │ │ ├── bottom_sheet_gender.dart │ │ │ ├── content_setting.dart │ │ │ ├── row_icon_text.dart │ │ │ └── bottom_sheet_choose_option.dart │ ├── auth │ │ ├── domain │ │ │ ├── entities │ │ │ │ ├── auth_type.dart │ │ │ │ └── social.dart │ │ │ ├── repositories │ │ │ │ └── auth_repository.dart │ │ │ └── usecases │ │ │ │ ├── sign_out.dart │ │ │ │ ├── check_logined.dart │ │ │ │ └── sign_in_with_social.dart │ │ ├── presentation │ │ │ ├── bloc │ │ │ │ ├── auth_state.dart │ │ │ │ └── auth_event.dart │ │ │ └── widgets │ │ │ │ └── sign_in_button.dart │ │ └── data │ │ │ ├── datasources │ │ │ ├── auth_local_datasource.dart │ │ │ └── auth_remote_datasource.dart │ │ │ └── repositories │ │ │ └── auth_repository_impl.dart │ ├── app │ │ ├── bloc │ │ │ └── app_bloc.dart │ │ ├── screens │ │ │ └── scaffold_wrapper.dart │ │ └── app.dart │ └── stream │ │ ├── provider │ │ └── hearts_provider.dart │ │ └── presentation │ │ ├── widgets │ │ ├── app_bar_stream.dart │ │ ├── floating_hearts.dart │ │ ├── viewer_widget.dart │ │ ├── hearts_animation.dart │ │ └── name_live_widget.dart │ │ └── screens │ │ └── stream_screen.dart └── main.dart ├── linux ├── .gitignore ├── main.cc ├── flutter │ ├── generated_plugin_registrant.h │ ├── generated_plugin_registrant.cc │ └── generated_plugins.cmake └── my_application.h ├── ios ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── AppIcon-20.png │ │ │ ├── AppIcon-29.png │ │ │ ├── AppIcon-40.png │ │ │ ├── AppIcon-76.png │ │ │ ├── AppIcon-1024.png │ │ │ ├── AppIcon-20@2x.png │ │ │ ├── AppIcon-20@3x.png │ │ │ ├── AppIcon-29@2x.png │ │ │ ├── AppIcon-29@3x.png │ │ │ ├── AppIcon-40@2x.png │ │ │ ├── AppIcon-40@3x.png │ │ │ ├── AppIcon-60@2x.png │ │ │ ├── AppIcon-60@3x.png │ │ │ ├── AppIcon-76@2x.png │ │ │ └── AppIcon-83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ ├── Runner.entitlements │ ├── AppDelegate.swift │ ├── GoogleService-Info.plist │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── clean-pods.sh ├── Runner.xcodeproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── .gitignore └── Podfile ├── web ├── favicon.png ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png ├── manifest.json └── index.html ├── git-config.sh ├── assets ├── icons │ ├── ic_eye.png │ ├── ic_apple.png │ ├── ic_fire.png │ ├── ic_game.png │ ├── ic_google.png │ ├── ic_home.png │ ├── ic_moon.png │ ├── ic_nearby.png │ ├── ic_facebook.png │ ├── ic_sharing.png │ ├── launcher_icon.png │ └── ic_home_seleted.png └── images │ ├── stream_image.jpg │ └── img_start_stream.png ├── screenshots ├── photo_0.jpg ├── photo_1.jpeg ├── photo_2.jpeg ├── photo_3.jpeg ├── photo_4.jpeg ├── photo_5.jpeg ├── photo_6.jpeg ├── photo_7.jpeg └── launcher_icon_rounded.png ├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── launcher_icon.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── launcher_icon.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── launcher_icon.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── launcher_icon.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── launcher_icon.png │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── values-night │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── streamskit_mobile │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle └── build.gradle ├── macos ├── Runner │ ├── Configs │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ ├── Warnings.xcconfig │ │ └── AppInfo.xcconfig │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── app_icon_16.png │ │ │ ├── app_icon_32.png │ │ │ ├── app_icon_64.png │ │ │ ├── app_icon_1024.png │ │ │ ├── app_icon_128.png │ │ │ ├── app_icon_256.png │ │ │ ├── app_icon_512.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Release.entitlements │ ├── DebugProfile.entitlements │ ├── MainFlutterWindow.swift │ └── Info.plist ├── .gitignore ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Runner.xcodeproj │ └── project.xcworkspace │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── Podfile ├── windows ├── runner │ ├── resources │ │ └── app_icon.ico │ ├── resource.h │ ├── utils.h │ ├── runner.exe.manifest │ ├── flutter_window.h │ ├── main.cpp │ ├── CMakeLists.txt │ ├── utils.cpp │ └── flutter_window.cpp ├── .gitignore └── flutter │ ├── generated_plugin_registrant.h │ ├── generated_plugin_registrant.cc │ └── generated_plugins.cmake ├── test ├── fixtures │ ├── fixture_reader.dart │ └── live_stream_model.json └── features │ └── home │ ├── domain │ └── usecases │ │ ├── get_list_live_stream_test.dart │ │ └── get_list_live_stream_test.mocks.dart │ └── data │ ├── repositories │ └── live_stream_repository_test.dart │ └── models │ └── live_stream_model_test.dart ├── .vscode └── settings.json ├── tools-helper.sh ├── .githooks ├── pre-commit └── pre-push ├── .github ├── workflows │ ├── check_issues.yaml │ └── main.yaml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── SECURITY.md ├── .gitignore ├── run.sh ├── analysis_options.yaml ├── .metadata └── README.md /lib/core/app/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/core/error/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/core/types/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/core/util/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/core/app/colors/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/core/app/lang/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/core/app/themes/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/core/injection/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/core/navigator/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/core/network/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/core/usecase/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/features/chat/data/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/features/chat/domain/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/features/home/data/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/features/search/data/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/features/profile/data/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/features/profile/domain/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/features/search/domain/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /lib/core/app/constant/socket_events.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/core/app/constant/data_channel_events.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/features/home/data/datasources/remote_live_stream_source.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/core/util/styles/style.dart: -------------------------------------------------------------------------------- 1 | export 'home_style.dart'; 2 | export 'auth_style.dart'; 3 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/web/favicon.png -------------------------------------------------------------------------------- /git-config.sh: -------------------------------------------------------------------------------- 1 | cd .githooks 2 | chmod +x pre-commit 3 | chmod +x pre-push 4 | git config core.hooksPath .githooks -------------------------------------------------------------------------------- /assets/icons/ic_eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/assets/icons/ic_eye.png -------------------------------------------------------------------------------- /lib/features/auth/domain/entities/auth_type.dart: -------------------------------------------------------------------------------- 1 | enum AuthType { 2 | google, 3 | facebook, 4 | apple, 5 | } 6 | -------------------------------------------------------------------------------- /screenshots/photo_0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/screenshots/photo_0.jpg -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/web/icons/Icon-512.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /assets/icons/ic_apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/assets/icons/ic_apple.png -------------------------------------------------------------------------------- /assets/icons/ic_fire.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/assets/icons/ic_fire.png -------------------------------------------------------------------------------- /assets/icons/ic_game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/assets/icons/ic_game.png -------------------------------------------------------------------------------- /assets/icons/ic_google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/assets/icons/ic_google.png -------------------------------------------------------------------------------- /assets/icons/ic_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/assets/icons/ic_home.png -------------------------------------------------------------------------------- /assets/icons/ic_moon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/assets/icons/ic_moon.png -------------------------------------------------------------------------------- /assets/icons/ic_nearby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/assets/icons/ic_nearby.png -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /screenshots/photo_1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/screenshots/photo_1.jpeg -------------------------------------------------------------------------------- /screenshots/photo_2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/screenshots/photo_2.jpeg -------------------------------------------------------------------------------- /screenshots/photo_3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/screenshots/photo_3.jpeg -------------------------------------------------------------------------------- /screenshots/photo_4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/screenshots/photo_4.jpeg -------------------------------------------------------------------------------- /screenshots/photo_5.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/screenshots/photo_5.jpeg -------------------------------------------------------------------------------- /screenshots/photo_6.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/screenshots/photo_6.jpeg -------------------------------------------------------------------------------- /screenshots/photo_7.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/screenshots/photo_7.jpeg -------------------------------------------------------------------------------- /assets/icons/ic_facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/assets/icons/ic_facebook.png -------------------------------------------------------------------------------- /assets/icons/ic_sharing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/assets/icons/ic_sharing.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /lib/core/app/constant/endpoints.dart: -------------------------------------------------------------------------------- 1 | class Endpoints { 2 | // Auth 3 | static const String signIn = 'auth/signIn'; 4 | } 5 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /assets/icons/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/assets/icons/launcher_icon.png -------------------------------------------------------------------------------- /assets/images/stream_image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/assets/images/stream_image.jpg -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /assets/icons/ic_home_seleted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/assets/icons/ic_home_seleted.png -------------------------------------------------------------------------------- /assets/images/img_start_stream.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/assets/images/img_start_stream.png -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /screenshots/launcher_icon_rounded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/screenshots/launcher_icon_rounded.png -------------------------------------------------------------------------------- /windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /ios/clean-pods.sh: -------------------------------------------------------------------------------- 1 | 2 | rm -rf Pods 3 | rm -rf Podfile.lock 4 | flutter clean 5 | flutter pub get 6 | # pod install --repo-update 7 | arch -x86_64 pod install 8 | -------------------------------------------------------------------------------- /test/fixtures/fixture_reader.dart: -------------------------------------------------------------------------------- 1 | // Dart imports: 2 | import 'dart:io'; 3 | 4 | String fixture(String name) => File('test/fixtures/$name').readAsStringSync(); 5 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/android/app/src/main/res/mipmap-hdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/android/app/src/main/res/mipmap-mdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-76.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-1024.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambiengcode/flutter-live-stream-ui/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "dart.flutterSdkPath": "/Users/lambiengcode/Documents/askany_mobile/F:\\flutter_windows_2.8.1-stable\\flutter", 3 | "java.configuration.updateBuildConfiguration": "interactive" 4 | } -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/streamskit_mobile/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.streams.kit 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /lib/core/util/styles/auth_style.dart: -------------------------------------------------------------------------------- 1 | const String logoGoogle = 'assets/icons/ic_google.png'; 2 | const String logoFacebook = 'assets/icons/ic_facebook.png'; 3 | const String logoApple = 'assets/icons/ic_apple.png'; 4 | -------------------------------------------------------------------------------- /linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/core/app/constants.dart: -------------------------------------------------------------------------------- 1 | const double inchToDP = 160; 2 | 3 | // Delay times - miliseconds 4 | const int delay200ms = 200; 5 | const int delay500ms = 500; 6 | const int delayASecond = 1000; 7 | const int delayHalfSecond = 500; 8 | -------------------------------------------------------------------------------- /lib/core/types/service_method.dart: -------------------------------------------------------------------------------- 1 | enum ServiceMethod { 2 | get, 3 | post, 4 | put, 5 | patch, 6 | delete, 7 | } 8 | 9 | extension ServiceDescription on ServiceMethod { 10 | String get methodName => name.toUpperCase(); 11 | } 12 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip 6 | -------------------------------------------------------------------------------- /macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/core/network/url_launcher_helper.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:url_launcher/url_launcher.dart'; 3 | 4 | class UrlLauncherHelper { 5 | static Future launchUrlString(Uri uri) async { 6 | if (await canLaunchUrl(uri)) { 7 | await launchUrl(uri, mode: LaunchMode.inAppWebView); 8 | } else {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /lib/core/error/failure.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:equatable/equatable.dart'; 3 | 4 | abstract class Failure extends Equatable { 5 | @override 6 | List get props => []; 7 | } 8 | 9 | // General failures 10 | class CannotFoundItem extends Failure {} 11 | 12 | class CannotParseItem extends Failure {} 13 | 14 | class NullValue extends Failure {} 15 | -------------------------------------------------------------------------------- /windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/bloc/auth_state.dart: -------------------------------------------------------------------------------- 1 | part of 'auth_bloc.dart'; 2 | 3 | abstract class AuthState extends Equatable { 4 | const AuthState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class AuthInitial extends AuthState {} 11 | 12 | class AuthSuccess extends AuthState {} 13 | 14 | class AuthFailure extends AuthState {} 15 | 16 | class Authenticating extends AuthState {} 17 | -------------------------------------------------------------------------------- /lib/features/home/domain/repositories/live_stream_repository.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:dartz/dartz.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/error/failure.dart'; 6 | import 'package:streamskit_mobile/features/home/data/model/live_stream_model.dart'; 7 | 8 | abstract class LiveStreamRepository { 9 | Either> getLiveStreams(); 10 | } 11 | -------------------------------------------------------------------------------- /macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /lib/core/app/constant/constants.dart: -------------------------------------------------------------------------------- 1 | // Remote Data 2 | const String serviceBaseEndpoint = 'https://streamos.tk/'; 3 | 4 | // Utils 5 | const double inchToDP = 160; 6 | 7 | // Delay times - miliseconds 8 | const int delay100ms = 100; 9 | const int delay200ms = 200; 10 | const int durationDefaultAnimation = 300; 11 | const int delay500ms = 500; 12 | const int delayASecond = 1000; 13 | const int connectTimeOut = 5000; 14 | const int receiveTimeOut = 5000; 15 | -------------------------------------------------------------------------------- /lib/core/util/styles/home_style.dart: -------------------------------------------------------------------------------- 1 | const String launcherIcon = 'assets/icons/launcher_icon.png'; 2 | const String imageStartStream = 'assets/images/img_start_stream.png'; 3 | 4 | const String iconFire = 'assets/icons/ic_fire.png'; 5 | const String iconNearby = 'assets/icons/ic_nearby.png'; 6 | const String iconGame = 'assets/icons/ic_game.png'; 7 | const String iconSharing = 'assets/icons/ic_sharing.png'; 8 | const String iconEye = 'assets/icons/ic_eye.png'; 9 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/bloc/auth_event.dart: -------------------------------------------------------------------------------- 1 | part of 'auth_bloc.dart'; 2 | 3 | abstract class AuthEvent extends Equatable { 4 | const AuthEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class OnAuthCheckEvent extends AuthEvent {} 11 | 12 | class SignInEvent extends AuthEvent { 13 | final AuthType authType; 14 | const SignInEvent({required this.authType}); 15 | } 16 | 17 | class SignOutEvent extends AuthEvent {} 18 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tools-helper.sh: -------------------------------------------------------------------------------- 1 | echo "1. import_sorter" 2 | echo "2. dart_code_metrics" 3 | echo "3. injectable" 4 | 5 | while : 6 | do 7 | read -p "Run with: " input 8 | case $input in 9 | 1) 10 | flutter pub run import_sorter:main 11 | break 12 | ;; 13 | 2) 14 | flutter pub run dart_code_metrics:metrics analyze lib 15 | break 16 | ;; 17 | 3) 18 | flutter packages pub run build_runner build 19 | break 20 | ;; 21 | *) 22 | ;; 23 | esac 24 | done -------------------------------------------------------------------------------- /lib/features/auth/domain/repositories/auth_repository.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:dartz/dartz.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/error/failure.dart'; 6 | import 'package:streamskit_mobile/core/usecase/usecase.dart'; 7 | 8 | abstract class AuthRepository { 9 | Future> signIn(Params params); 10 | 11 | Either checkSignined(); 12 | 13 | Either signOut(); 14 | } 15 | -------------------------------------------------------------------------------- /lib/core/app/constant/storage_keys.dart: -------------------------------------------------------------------------------- 1 | class StorageKeys { 2 | // Box Variables 3 | static const String boxSystem = 'boxSystem'; 4 | static const String boxAuth = 'boxAuth'; 5 | static const String boxUser = 'boxUser'; 6 | static const String boxLiveStreams = 'boxLiveStreams'; 7 | 8 | // Key in Box - Auth 9 | static const String accessToken = 'accessToken'; 10 | 11 | // Key in Box - Live Streams 12 | static const String liveStreamsKey = 'liveStreamsKey'; 13 | } 14 | -------------------------------------------------------------------------------- /linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/live_stream_model.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "peopleParticipant": 910, 4 | "type": 1, 5 | "urlToImage": "" 6 | }, 7 | { 8 | "peopleParticipant": 910, 9 | "type": 2, 10 | "urlToImage": "" 11 | }, 12 | { 13 | "peopleParticipant": 910, 14 | "type": 3, 15 | "urlToImage": "" 16 | }, 17 | { 18 | "peopleParticipant": 910, 19 | "type": 4, 20 | "urlToImage": "" 21 | } 22 | ] -------------------------------------------------------------------------------- /lib/core/util/after_layout_mixin.dart: -------------------------------------------------------------------------------- 1 | // Dart imports: 2 | import 'dart:async'; 3 | 4 | // Flutter imports: 5 | import 'package:flutter/material.dart'; 6 | 7 | mixin AfterLayoutMixin on State { 8 | @override 9 | void initState() { 10 | super.initState(); 11 | WidgetsBinding.instance.endOfFrame.then( 12 | (_) { 13 | if (mounted) afterFirstLayout(context); 14 | }, 15 | ); 16 | } 17 | 18 | FutureOr afterFirstLayout(BuildContext context); 19 | } 20 | -------------------------------------------------------------------------------- /windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /.githooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | printf "\e[33;1m%s\e[0m\n" 'Running the Flutter formatter' 4 | flutter format . 5 | printf "\e[33;1m%s\e[0m\n" 'Finished running the Flutter formatter' 6 | printf "\e[33;1m%s\e[0m\n" 'Running the import_sorter' 7 | flutter pub run import_sorter:main 8 | printf "\e[33;1m%s\e[0m\n" 'Finished running the import_sorter' 9 | 10 | branch="$(git rev-parse --abbrev-ref HEAD)" 11 | 12 | if [ "$branch" = "master" ]; then 13 | echo "You can't commit directly to master branch" 14 | exit 1 15 | fi -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /lib/core/injection/injection_container.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:get_it/get_it.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | 5 | // Project imports: 6 | import 'package:streamskit_mobile/core/injection/injection_container.config.dart'; 7 | 8 | final getIt = GetIt.instance; 9 | 10 | @InjectableInit( 11 | initializerName: r'$initGetIt', // default 12 | preferRelativeImports: true, // default 13 | asExtension: false, // default 14 | ) 15 | void configureDependencies() => $initGetIt(getIt); 16 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.github/workflows/check_issues.yaml: -------------------------------------------------------------------------------- 1 | name: Analyze project 2 | 3 | on: 4 | push: 5 | branches: 6 | - "*/*" 7 | 8 | jobs: 9 | test: 10 | name: Analyze & Test 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v1 14 | - uses: actions/setup-java@v1 15 | with: 16 | java-version: "12.x" 17 | - uses: subosito/flutter-action@v1 18 | with: 19 | flutter-version: "3.3.4" 20 | - run: flutter pub get 21 | - run: flutter analyze 22 | - run: flutter test 23 | -------------------------------------------------------------------------------- /lib/core/util/sizer_custom/sizer.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Urmish patel on 2018/9/29. 3 | * email: urmishpatel9@gmail.com 4 | */ 5 | library sizer; 6 | 7 | // Dart imports: 8 | import 'dart:io'; 9 | import 'dart:math' as math; 10 | 11 | // Flutter imports: 12 | import 'package:flutter/foundation.dart' show kIsWeb; 13 | import 'package:flutter/widgets.dart'; 14 | 15 | // Project imports: 16 | import 'package:streamskit_mobile/core/app/constant/constants.dart'; 17 | 18 | part 'extension.dart'; 19 | 20 | part 'util.dart'; 21 | 22 | part 'widget.dart'; 23 | -------------------------------------------------------------------------------- /lib/core/util/common/pull_to_refresh/pull_to_refresh.dart: -------------------------------------------------------------------------------- 1 | export 'src/smart_refresher.dart'; 2 | export 'src/indicator/classic_indicator.dart'; 3 | export 'src/indicator/waterdrop_header.dart'; 4 | export 'src/indicator/custom_indicator.dart'; 5 | export 'src/internals/refresh_physics.dart'; 6 | export "src/internals/indicator_wrap.dart"; 7 | export 'src/indicator/link_indicator.dart'; 8 | export 'src/indicator/material_indicator.dart'; 9 | export 'src/indicator/bezier_indicator.dart'; 10 | export 'src/indicator/twolevel_indicator.dart'; 11 | export 'src/internals/refresh_localizations.dart'; 12 | -------------------------------------------------------------------------------- /lib/core/util/logger.dart: -------------------------------------------------------------------------------- 1 | // Dart imports: 2 | import 'dart:developer' as developer; 3 | 4 | // Flutter imports: 5 | import 'package:flutter/foundation.dart'; 6 | 7 | class UtilLogger { 8 | static const String tag = "SALEBOLT"; 9 | 10 | static log([String tag = tag, dynamic msg]) { 11 | if (kDebugMode) { 12 | developer.log('$msg', name: tag); 13 | } 14 | } 15 | 16 | ///Singleton factory 17 | static final UtilLogger _instance = UtilLogger._internal(); 18 | 19 | factory UtilLogger() { 20 | return _instance; 21 | } 22 | 23 | UtilLogger._internal(); 24 | } 25 | -------------------------------------------------------------------------------- /.githooks/pre-push: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [[ `git status --porcelain` ]]; then 4 | printf "\e[31;1m%s\e[0m\n" 'This script needs to run against committed code only. Please commit or stash you changes.' 5 | exit 1 6 | fi 7 | printf "\e[33;1m%s\e[0m\n" 'Running the Flutter analyzer' 8 | flutter analyze 9 | if [ $? -ne 0 ]; then 10 | printf "\e[31;1m%s\e[0m\n" 'Flutter analyzer error' 11 | exit 1 12 | fi 13 | flutter test 14 | if [ $? -ne 0 ]; then 15 | printf "\e[31;1m%s\e[0m\n" 'Flutter test error' 16 | exit 1 17 | fi 18 | printf "\e[33;1m%s\e[0m\n" 'Finished running the Flutter analyzer' 19 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | import Firebase 4 | 5 | @UIApplicationMain 6 | @objc class AppDelegate: FlutterAppDelegate { 7 | override func application( 8 | _ application: UIApplication, 9 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 10 | ) -> Bool { 11 | /// Configuration 12 | FirebaseApp.configure() 13 | GeneratedPluginRegistrant.register(with: self) 14 | application.registerForRemoteNotifications() 15 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /lib/core/util/styles/search_style.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/app/colors/app_color.dart'; 6 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 7 | 8 | /// Text size: 11 color: mGB weight: 700 9 | TextStyle text11w700mGB = TextStyle( 10 | color: mGB, 11 | fontSize: 11.sp, 12 | fontWeight: FontWeight.w700, 13 | overflow: TextOverflow.ellipsis, 14 | ); 15 | 16 | ///Text size: 9 color: mGB 17 | TextStyle text9mGB = TextStyle( 18 | color: mGB, 19 | fontSize: 9.sp, 20 | overflow: TextOverflow.ellipsis, 21 | height: 1.4, 22 | ); 23 | -------------------------------------------------------------------------------- /lib/core/util/styles/chat_style.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/app/colors/app_color.dart'; 6 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 7 | 8 | Divider dividerChat(BuildContext context) { 9 | return Divider( 10 | color: colorDividerTimeline, 11 | thickness: 0.2, 12 | height: 0.2, 13 | ); 14 | } 15 | 16 | Divider dividerChatWithPadding(context) { 17 | return Divider( 18 | color: colorDividerTimeline, 19 | thickness: 0.2, 20 | height: 0.2, 21 | indent: 12.sp, 22 | endIndent: 12.sp, 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = streamskit_mobile 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.example.streamskitMobile 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2022 com.example. All rights reserved. 15 | -------------------------------------------------------------------------------- /lib/features/auth/domain/usecases/sign_out.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:dartz/dartz.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | 5 | // Project imports: 6 | import 'package:streamskit_mobile/core/error/failure.dart'; 7 | import 'package:streamskit_mobile/core/usecase/usecase.dart'; 8 | import 'package:streamskit_mobile/features/auth/domain/repositories/auth_repository.dart'; 9 | 10 | @lazySingleton 11 | class SignOut implements UseCase { 12 | final AuthRepository repository; 13 | 14 | const SignOut({required this.repository}); 15 | 16 | @override 17 | Either call(NoParams noParams) { 18 | return repository.signOut(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /lib/features/auth/domain/usecases/check_logined.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:dartz/dartz.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | 5 | // Project imports: 6 | import 'package:streamskit_mobile/core/error/failure.dart'; 7 | import 'package:streamskit_mobile/core/usecase/usecase.dart'; 8 | import 'package:streamskit_mobile/features/auth/domain/repositories/auth_repository.dart'; 9 | 10 | @lazySingleton 11 | class CheckLogined implements UseCase { 12 | final AuthRepository repository; 13 | 14 | const CheckLogined({required this.repository}); 15 | 16 | @override 17 | Either call(NoParams noParams) { 18 | return repository.checkSignined(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.6.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.1.2' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /lib/core/app/config/base_local_data.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:hive/hive.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/app/constant/storage_keys.dart'; 6 | import 'package:streamskit_mobile/core/util/path_helper.dart'; 7 | 8 | class BaseLocalData { 9 | static Future initialBox() async { 10 | String path = await PathHelper.localStoreDirStreamOS; 11 | Hive.init(path); 12 | await Hive.openBox(StorageKeys.boxSystem); 13 | await openBoxApp(); 14 | } 15 | 16 | static Future openBoxApp() async { 17 | await Hive.openBox(StorageKeys.boxAuth); 18 | await Hive.openBox(StorageKeys.boxUser); 19 | await Hive.openBox(StorageKeys.boxLiveStreams); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/core/usecase/usecase.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:dartz/dartz.dart'; 3 | import 'package:equatable/equatable.dart'; 4 | 5 | // Project imports: 6 | import 'package:streamskit_mobile/core/error/failure.dart'; 7 | 8 | abstract class UseCase { 9 | Either call(Params params); 10 | } 11 | 12 | abstract class UseCaseFuture { 13 | Future> call(Params params); 14 | } 15 | 16 | class NoParams extends Equatable { 17 | @override 18 | List get props => []; 19 | } 20 | 21 | class Params extends Equatable { 22 | final Object object; 23 | 24 | const Params({required this.object}); 25 | 26 | @override 27 | List get props => [object]; 28 | } 29 | -------------------------------------------------------------------------------- /lib/features/app/bloc/app_bloc.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/injection/injection_container.dart'; 6 | import 'package:streamskit_mobile/features/auth/presentation/bloc/auth_bloc.dart'; 7 | 8 | class AppBloc { 9 | static final AuthBloc authBloc = getIt(); 10 | static final List providers = [ 11 | BlocProvider( 12 | create: (context) => authBloc..add(OnAuthCheckEvent()), 13 | ), 14 | ]; 15 | 16 | ///Singleton factory 17 | static final AppBloc _instance = AppBloc._internal(); 18 | 19 | factory AppBloc() { 20 | return _instance; 21 | } 22 | 23 | AppBloc._internal(); 24 | } 25 | -------------------------------------------------------------------------------- /windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | -------------------------------------------------------------------------------- /lib/core/navigator/app_routes.dart: -------------------------------------------------------------------------------- 1 | class Routes { 2 | static const rootRoute = '/'; 3 | static const splashRoute = '/splash'; 4 | static const authenticationRoute = '/authentication'; 5 | 6 | // Chat 7 | static const chatRoute = '/chat'; 8 | 9 | // Stream 10 | static const streamRoute = '/stream'; 11 | 12 | //Profile 13 | static const profileRoute = '/profile'; 14 | static const editProfileRoute = '/editProfile'; 15 | static const editUsernameRoute = '/editUsernameProfile'; 16 | static const editDescriptionRoute = '/editDescriptionProfile'; 17 | static const editPhoneNumberRoute = '/editPhoneNumber'; 18 | 19 | //Setting 20 | static const settingRoute = '/setting'; 21 | 22 | //Search 23 | static const searchRoute = '/search'; 24 | } 25 | -------------------------------------------------------------------------------- /lib/features/stream/provider/hearts_provider.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/features/stream/presentation/widgets/hearts_animation.dart'; 6 | 7 | class FloatingHeartsProvider with ChangeNotifier { 8 | final List _hearts = []; 9 | int _key = 0; 10 | 11 | List get hearts => _hearts; 12 | 13 | void addHeart() { 14 | _hearts.addAll([ 15 | HeartAnimation(key: Key((_key + 1).toString())), 16 | HeartAnimation(key: Key((_key + 2).toString())), 17 | HeartAnimation(key: Key((_key + 3).toString())) 18 | ]); 19 | _key += 3; 20 | notifyListeners(); 21 | } 22 | 23 | void removeHeart(Key? key) { 24 | _hearts.clear(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | 12 | void fl_register_plugins(FlPluginRegistry* registry) { 13 | g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = 14 | fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); 15 | file_selector_plugin_register_with_registrar(file_selector_linux_registrar); 16 | g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = 17 | fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); 18 | url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/home/domain/usecases/get_list_live_streaming.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:dartz/dartz.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | 5 | // Project imports: 6 | import 'package:streamskit_mobile/core/error/failure.dart'; 7 | import 'package:streamskit_mobile/core/usecase/usecase.dart'; 8 | import 'package:streamskit_mobile/features/home/data/model/live_stream_model.dart'; 9 | import 'package:streamskit_mobile/features/home/domain/repositories/live_stream_repository.dart'; 10 | 11 | @lazySingleton 12 | class GetListLiveStreaming implements UseCase, NoParams> { 13 | final LiveStreamRepository repository; 14 | 15 | const GetListLiveStreaming({required this.repository}); 16 | 17 | @override 18 | Either> call(NoParams params) { 19 | return repository.getLiveStreams(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | 35 | # Symbolication related 36 | app.*.symbols 37 | 38 | # Obfuscation related 39 | app.*.map.json 40 | 41 | # Android Studio will place build artifacts here 42 | /android/app/debug 43 | /android/app/profile 44 | /android/app/release 45 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | file_selector_linux 7 | url_launcher_linux 8 | ) 9 | 10 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 11 | ) 12 | 13 | set(PLUGIN_BUNDLED_LIBRARIES) 14 | 15 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 16 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 17 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 20 | endforeach(plugin) 21 | 22 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 23 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 25 | endforeach(ffi_plugin) 26 | -------------------------------------------------------------------------------- /lib/features/home/presentation/splash_screen.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 6 | import 'package:streamskit_mobile/core/util/styles/style.dart'; 7 | 8 | class SplashScreen extends StatelessWidget { 9 | const SplashScreen({super.key}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | body: Column( 15 | crossAxisAlignment: CrossAxisAlignment.center, 16 | mainAxisAlignment: MainAxisAlignment.center, 17 | children: [ 18 | Align( 19 | alignment: Alignment.center, 20 | child: Image.asset( 21 | launcherIcon, 22 | height: 240.sp, 23 | width: 240.sp, 24 | ), 25 | ), 26 | ], 27 | ), 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/features/auth/domain/usecases/sign_in_with_social.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:dartz/dartz.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | 5 | // Project imports: 6 | import 'package:streamskit_mobile/core/error/failure.dart'; 7 | import 'package:streamskit_mobile/core/usecase/usecase.dart'; 8 | import 'package:streamskit_mobile/features/auth/domain/entities/social.dart'; 9 | import 'package:streamskit_mobile/features/auth/domain/repositories/auth_repository.dart'; 10 | 11 | @lazySingleton 12 | class SignInWithSocial implements UseCaseFuture { 13 | final AuthRepository repository; 14 | 15 | const SignInWithSocial({required this.repository}); 16 | 17 | @override 18 | Future> call(Params params) async { 19 | if (params.object is! SocialValue) { 20 | return Left(CannotParseItem()); 21 | } 22 | 23 | return repository.signIn(params); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/features/home/data/repositories/live_stream_repository_impl.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:dartz/dartz.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | 5 | // Project imports: 6 | import 'package:streamskit_mobile/core/error/failure.dart'; 7 | import 'package:streamskit_mobile/features/home/data/datasources/local_live_stream_source.dart'; 8 | import 'package:streamskit_mobile/features/home/data/model/live_stream_model.dart'; 9 | import 'package:streamskit_mobile/features/home/domain/repositories/live_stream_repository.dart'; 10 | 11 | @LazySingleton(as: LiveStreamRepository) 12 | class LiveStreamRepositoryImpl implements LiveStreamRepository { 13 | final LocalLiveStreamSource localData; 14 | 15 | const LiveStreamRepositoryImpl({required this.localData}); 16 | 17 | @override 18 | Either> getLiveStreams() { 19 | return Right(localData.getLiveStreams()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | void RegisterPlugins(flutter::PluginRegistry* registry) { 15 | FileSelectorWindowsRegisterWithRegistrar( 16 | registry->GetRegistrarForPlugin("FileSelectorWindows")); 17 | FirebaseAuthPluginCApiRegisterWithRegistrar( 18 | registry->GetRegistrarForPlugin("FirebaseAuthPluginCApi")); 19 | FirebaseCorePluginCApiRegisterWithRegistrar( 20 | registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); 21 | UrlLauncherWindowsRegisterWithRegistrar( 22 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 23 | } 24 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | file_selector_windows 7 | firebase_auth 8 | firebase_core 9 | url_launcher_windows 10 | ) 11 | 12 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 13 | ) 14 | 15 | set(PLUGIN_BUNDLED_LIBRARIES) 16 | 17 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 18 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 19 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 20 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 21 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 22 | endforeach(plugin) 23 | 24 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 25 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 26 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 27 | endforeach(ffi_plugin) 28 | -------------------------------------------------------------------------------- /lib/features/auth/data/datasources/auth_local_datasource.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:hive/hive.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | 5 | // Project imports: 6 | import 'package:streamskit_mobile/core/app/constant/storage_keys.dart'; 7 | 8 | abstract class AuthLocalDataSource { 9 | String? getAccessToken(); 10 | void saveAccessToken(String accessToken); 11 | void clearAccessToken(); 12 | } 13 | 14 | @LazySingleton(as: AuthLocalDataSource) 15 | class AuthLocalDataSourceImpl implements AuthLocalDataSource { 16 | final Box hiveBox = Hive.box(StorageKeys.boxAuth); 17 | 18 | @override 19 | void clearAccessToken() { 20 | hiveBox.delete(StorageKeys.accessToken); 21 | } 22 | 23 | @override 24 | String? getAccessToken() { 25 | return hiveBox.get(StorageKeys.accessToken); 26 | } 27 | 28 | @override 29 | void saveAccessToken(String accessToken) { 30 | hiveBox.put(StorageKeys.accessToken, accessToken); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /lib/core/util/stop_watch_api.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:dio/dio.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/app/constant/constants.dart'; 6 | import 'package:streamskit_mobile/core/util/logger.dart'; 7 | 8 | class StopWatch { 9 | static Future stopWatchApi( 10 | Future Function() next, String method, String endpoint) async { 11 | DateTime startTime = DateTime.now(); 12 | var result = await next(); 13 | DateTime endTime = DateTime.now(); 14 | int duration = endTime.difference(startTime).inMilliseconds; 15 | if (duration >= delayASecond) { 16 | UtilLogger.log( 17 | 'WARNING RESPONSE TIME', '**********************************'); 18 | UtilLogger.log( 19 | 'WARNING RESPONSE TIME', '$method: $endpoint - ${duration}ms\n'); 20 | UtilLogger.log( 21 | 'WARNING RESPONSE TIME', '**********************************'); 22 | } 23 | return result; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/widgets/index_info_user.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/util/numeral/numeral.dart'; 6 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 7 | import 'package:streamskit_mobile/core/util/styles/profile_style.dart'; 8 | 9 | class IndexInfoUser extends StatelessWidget { 10 | final String titleIndex; 11 | final int numberIndex; 12 | const IndexInfoUser({ 13 | super.key, 14 | required this.titleIndex, 15 | required this.numberIndex, 16 | }); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Column( 21 | children: [ 22 | Text( 23 | Numeral(numberIndex).format(), 24 | style: text13w700mCL, 25 | ), 26 | SizedBox(height: 2.sp), 27 | Text( 28 | titleIndex, 29 | style: text11mCL, 30 | ), 31 | ], 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/core/util/sizer_custom/widget.dart: -------------------------------------------------------------------------------- 1 | part of 'sizer.dart'; 2 | 3 | /// Provides `Context`, `Orientation`, and `DeviceType` parameters to the builder function 4 | typedef ResponsiveBuild = Widget Function( 5 | BuildContext context, 6 | Orientation orientation, 7 | DeviceType deviceType, 8 | ); 9 | 10 | /// A widget that gets the device's details like orientation and constraints 11 | /// 12 | /// Usage: Wrap MaterialApp with this widget 13 | class Sizer extends StatelessWidget { 14 | const Sizer({super.key, required this.builder}); 15 | 16 | /// Builds the widget whenever the orientation changes 17 | final ResponsiveBuild builder; 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return LayoutBuilder(builder: (context, constraints) { 22 | return OrientationBuilder(builder: (context, orientation) { 23 | SizerUtil.setScreenSize(constraints, orientation); 24 | return builder(context, orientation, SizerUtil.deviceType); 25 | }); 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/features/app/screens/scaffold_wrapper.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 6 | 7 | class ScaffoldWrapper extends StatelessWidget { 8 | final bool isLoading; 9 | final Widget child; 10 | const ScaffoldWrapper({ 11 | super.key, 12 | this.isLoading = false, 13 | required this.child, 14 | }); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Stack( 19 | children: [ 20 | IgnorePointer( 21 | ignoring: isLoading, 22 | child: child, 23 | ), 24 | Visibility( 25 | visible: isLoading, 26 | child: Container( 27 | alignment: Alignment.center, 28 | color: const Color(0x80000000), 29 | child: CupertinoActivityIndicator( 30 | radius: 15.sp, 31 | ), 32 | ), 33 | ), 34 | ], 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/features/stream/presentation/widgets/app_bar_stream.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 6 | import 'package:streamskit_mobile/features/stream/presentation/widgets/name_live_widget.dart'; 7 | import 'package:streamskit_mobile/features/stream/presentation/widgets/viewer_widget.dart'; 8 | 9 | class AppBarStream extends StatelessWidget { 10 | const AppBarStream({super.key}); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Container( 15 | padding: EdgeInsets.symmetric(vertical: 16.sp), 16 | child: Row( 17 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 18 | children: [ 19 | const Expanded( 20 | child: FullnameLiveWidget(), 21 | ), 22 | SizedBox( 23 | width: 6.sp, 24 | ), 25 | const ViewerWidget(), 26 | ], 27 | ), 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /lib/features/home/presentation/widgets/list_user_follow.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 6 | import 'package:streamskit_mobile/features/home/data/model/user_model.dart'; 7 | import 'package:streamskit_mobile/features/home/presentation/widgets/user_widget.dart'; 8 | 9 | class ListUserFollow extends StatelessWidget { 10 | const ListUserFollow({super.key}); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return SizedBox( 15 | height: 74.sp, 16 | width: double.infinity, 17 | child: ListView.builder( 18 | padding: EdgeInsets.symmetric(horizontal: 16.sp), 19 | itemCount: listUserFake.length, 20 | shrinkWrap: true, 21 | scrollDirection: Axis.horizontal, 22 | itemBuilder: ((context, index) { 23 | return UserWidget( 24 | userModel: listUserFake[index], 25 | ); 26 | }), 27 | ), 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/features/stream/presentation/widgets/floating_hearts.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | // ignore_for_file: depend_on_referenced_packages 3 | 4 | // Flutter imports: 5 | import 'package:flutter/material.dart'; 6 | 7 | // Package imports: 8 | import 'package:provider/provider.dart'; 9 | 10 | // Project imports: 11 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 12 | import 'package:streamskit_mobile/features/stream/provider/hearts_provider.dart'; 13 | 14 | class FloatingHeartsWidget extends StatelessWidget { 15 | const FloatingHeartsWidget({super.key}); 16 | @override 17 | Widget build(BuildContext context) { 18 | FloatingHeartsProvider floatingHeartsProvider = 19 | context.watch(); 20 | 21 | return Padding( 22 | padding: EdgeInsets.only(bottom: 8.sp), 23 | child: Align( 24 | alignment: Alignment.bottomRight, 25 | child: SizedBox( 26 | width: 40.sp, 27 | child: Stack(children: floatingHeartsProvider.hearts), 28 | ), 29 | ), 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/core/util/dio_transformer.dart: -------------------------------------------------------------------------------- 1 | // Dart imports: 2 | // ignore_for_file: deprecated_member_use 3 | 4 | import 'dart:convert'; 5 | 6 | // Flutter imports: 7 | import 'package:flutter/foundation.dart'; 8 | 9 | // Package imports: 10 | import 'package:dio/dio.dart'; 11 | 12 | /// Dio has already implemented a [DefaultTransformer], and as the default 13 | /// [Transformer]. If you want to custom the transformation of 14 | /// request/response data, you can provide a [Transformer] by your self, and 15 | /// replace the [DefaultTransformer] by setting the [dio.Transformer]. 16 | /// 17 | /// [DioTransformer] is especially for flutter, by which the json decoding 18 | /// will be in background with [compute] function. 19 | 20 | /// FlutterTransformer 21 | class DioTransformer extends DefaultTransformer { 22 | DioTransformer() : super(jsonDecodeCallback: _parseJson); 23 | } 24 | 25 | // Must be top-level function 26 | _parseAndDecode(String response) { 27 | return jsonDecode(response); 28 | } 29 | 30 | _parseJson(String text) { 31 | return compute(_parseAndDecode, text); 32 | } 33 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "streamskit_mobile", 3 | "short_name": "streamskit_mobile", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lib/core/navigator/transition_route.dart: -------------------------------------------------------------------------------- 1 | // Dart imports: 2 | import 'dart:io'; 3 | 4 | // Flutter imports: 5 | import 'package:flutter/material.dart'; 6 | 7 | // Project imports: 8 | import 'package:streamskit_mobile/core/app/constant/constants.dart'; 9 | 10 | class AppMaterialPageRoute extends MaterialPageRoute { 11 | AppMaterialPageRoute({ 12 | required super.builder, 13 | required RouteSettings super.settings, 14 | }); 15 | 16 | @override 17 | Duration get transitionDuration => const Duration( 18 | milliseconds: durationDefaultAnimation, 19 | ); 20 | 21 | @override 22 | @protected 23 | bool get hasScopedWillPopCallback { 24 | return Platform.isIOS ? true : false; 25 | } 26 | 27 | @override 28 | Widget buildTransitions(BuildContext context, Animation animation, 29 | Animation secondaryAnimation, Widget child) { 30 | final PageTransitionsTheme theme = Theme.of(context).pageTransitionsTheme; 31 | return theme.buildTransitions( 32 | this, 33 | context, 34 | animation, 35 | secondaryAnimation, 36 | child, 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/features/auth/data/datasources/auth_remote_datasource.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:dio/dio.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | 5 | // Project imports: 6 | import 'package:streamskit_mobile/core/app/config/base_remote_data.dart'; 7 | import 'package:streamskit_mobile/core/app/constant/endpoints.dart'; 8 | import 'package:streamskit_mobile/core/types/http_status_code.dart'; 9 | import 'package:streamskit_mobile/features/auth/domain/entities/social.dart'; 10 | 11 | abstract class AuthRemoteDataSource { 12 | Future signInWithSocial(SocialValue socialValue); 13 | } 14 | 15 | @LazySingleton(as: AuthRemoteDataSource) 16 | class AuthRemoteDataSourceImpl extends AuthRemoteDataSource { 17 | @override 18 | Future signInWithSocial(SocialValue socialValue) async { 19 | Map body = socialValue.toMap(); 20 | Response response = await BaseRemoteData().postRoute( 21 | Endpoints.signIn, 22 | body, 23 | ); 24 | 25 | if (response.statusCode == StatusCode.ok) { 26 | return response.data['data']; 27 | } 28 | 29 | return null; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | echo "0. Unit Test" 2 | echo "1. Debug with: environment is DEV" 3 | echo "2. Debug with: environment is STAGING" 4 | echo "3. Debug with: environment is PRODUCTION" 5 | echo "4. Release with: environment is DEV" 6 | echo "5. Release with: environment is STAGING" 7 | echo "6. Release with: environment is PRODUCTION" 8 | echo "7. Analyze" 9 | while : 10 | do 11 | read -p "Run with: " input 12 | case $input in 13 | 0) 14 | flutter test -r expanded 15 | break 16 | ;; 17 | 1) 18 | flutter run --dart-define="lambiengcode=DEV" 19 | break 20 | ;; 21 | 2) 22 | flutter run --dart-define="lambiengcode=STAGING" 23 | break 24 | ;; 25 | 3) 26 | flutter run --dart-define="lambiengcode=PRODUCTION" 27 | break 28 | ;; 29 | 4) 30 | flutter run --dart-define="lambiengcode=DEV" --release 31 | break 32 | ;; 33 | 5) 34 | flutter run --dart-define="lambiengcode=STAGING" --release 35 | break 36 | ;; 37 | 6) 38 | flutter run --dart-define="lambiengcode=PRODUCTION" --release 39 | break 40 | ;; 41 | 7) 42 | flutter analyze 43 | break 44 | ;; 45 | *) 46 | ;; 47 | esac 48 | done -------------------------------------------------------------------------------- /lib/core/util/custom_image/place_holder_image.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/app/colors/app_color.dart'; 6 | import 'package:streamskit_mobile/core/util/shimmer/fade_shimmer.dart'; 7 | 8 | class PlaceHolderImage extends StatelessWidget { 9 | final double height; 10 | final double width; 11 | final BoxShape shape; 12 | final BorderRadiusGeometry? borderRadius; 13 | const PlaceHolderImage({ 14 | super.key, 15 | required this.height, 16 | required this.width, 17 | required this.shape, 18 | required this.borderRadius, 19 | }); 20 | @override 21 | Widget build(BuildContext context) { 22 | return shape == BoxShape.circle 23 | ? FadeShimmer.round( 24 | size: height, 25 | highlightColor: colorPink, 26 | baseColor: mCM, 27 | ) 28 | : FadeShimmer( 29 | width: width, 30 | height: height, 31 | highlightColor: colorPink, 32 | baseColor: mCM, 33 | borderRadius: borderRadius, 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/features/home/presentation/widgets/button_circle.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Package imports: 5 | import 'package:phosphor_flutter/phosphor_flutter.dart'; 6 | 7 | // Project imports: 8 | import 'package:streamskit_mobile/core/app/colors/app_color.dart'; 9 | import 'package:streamskit_mobile/core/util/common/touchable_opacity.dart'; 10 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 11 | 12 | class ButtonCircle extends StatelessWidget { 13 | final IconData? icon; 14 | final Function() onTap; 15 | const ButtonCircle({super.key, required this.icon, required this.onTap}); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return TouchableOpacity( 20 | onTap: onTap, 21 | child: Container( 22 | decoration: BoxDecoration( 23 | color: fCD, 24 | shape: BoxShape.circle, 25 | ), 26 | padding: EdgeInsets.all(7.sp), 27 | child: Icon( 28 | icon ?? PhosphorIcons.moonLight, 29 | color: Colors.white, 30 | size: 18.sp, 31 | ), 32 | ), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/widgets/circle_icon.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/util/common/touchable_opacity.dart'; 6 | 7 | class CircleIcon extends StatelessWidget { 8 | final IconData icon; 9 | final Function()? onTap; 10 | final Color? colorIcon; 11 | final Color? backgroundIcon; 12 | final double? sizeIcon; 13 | const CircleIcon({ 14 | super.key, 15 | required this.icon, 16 | this.onTap, 17 | this.colorIcon, 18 | this.backgroundIcon, 19 | this.sizeIcon, 20 | }); 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return TouchableOpacity( 25 | onTap: onTap ?? () {}, 26 | child: Container( 27 | padding: const EdgeInsets.all(8), 28 | decoration: BoxDecoration( 29 | shape: BoxShape.circle, 30 | color: backgroundIcon ?? const Color(0xff5a5959), 31 | ), 32 | child: Icon( 33 | icon, 34 | color: colorIcon ?? Colors.white, 35 | size: sizeIcon, 36 | ), 37 | ), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/core/app/application.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/app/config/base_local_data.dart'; 6 | import 'package:streamskit_mobile/core/app/config/base_remote_data.dart'; 7 | import 'package:streamskit_mobile/core/injection/injection_container.dart'; 8 | import 'package:streamskit_mobile/core/util/path_helper.dart'; 9 | 10 | class Application { 11 | /// [Production - Dev] 12 | static Future initialAppLication() async { 13 | try { 14 | // Init dependency injection 15 | configureDependencies(); 16 | 17 | // Prepare path cache 18 | await PathHelper.createDirStreamOS(); 19 | 20 | // Init Hive 21 | await BaseLocalData.initialBox(); 22 | 23 | // Configure Dio [Cookie, Retry, Transformer] 24 | await BaseRemoteData.configureDio(); 25 | } catch (error) { 26 | debugPrint(error.toString()); 27 | } 28 | } 29 | 30 | ///Singleton factory 31 | static final Application _instance = Application._internal(); 32 | 33 | factory Application() { 34 | return _instance; 35 | } 36 | 37 | Application._internal(); 38 | } 39 | -------------------------------------------------------------------------------- /macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /lib/core/util/app_bars/appbar_none.dart: -------------------------------------------------------------------------------- 1 | // Dart imports: 2 | import 'dart:io'; 3 | 4 | // Flutter imports: 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter/services.dart'; 7 | 8 | AppBar appBarBrighnessDark({ 9 | required BuildContext context, 10 | Brightness? brightness, 11 | Color? backgroundColor, 12 | }) { 13 | return AppBar( 14 | toolbarHeight: 0.0, 15 | systemOverlayStyle: SystemUiOverlayStyle( 16 | statusBarColor: Colors.transparent, 17 | statusBarBrightness: (brightness ?? Theme.of(context).brightness) == 18 | (Platform.isAndroid ? Brightness.dark : Brightness.light) 19 | ? Brightness.light 20 | : Brightness.dark, 21 | statusBarIconBrightness: (brightness ?? Theme.of(context).brightness) == 22 | (Platform.isAndroid ? Brightness.dark : Brightness.light) 23 | ? Brightness.light 24 | : Brightness.dark, 25 | ), 26 | backgroundColor: backgroundColor ?? Colors.transparent, 27 | surfaceTintColor: 28 | backgroundColor ?? Theme.of(context).scaffoldBackgroundColor, 29 | elevation: 0.0, 30 | automaticallyImplyLeading: false, 31 | centerTitle: true, 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | // Dart imports: 2 | import 'dart:async'; 3 | 4 | // Flutter imports: 5 | import 'package:flutter/material.dart'; 6 | 7 | // Package imports: 8 | import 'package:firebase_core/firebase_core.dart'; 9 | import 'package:firebase_crashlytics/firebase_crashlytics.dart'; 10 | import 'package:flutter_bloc/flutter_bloc.dart'; 11 | 12 | // Project imports: 13 | import 'package:streamskit_mobile/core/app/application.dart'; 14 | import 'package:streamskit_mobile/features/app/app.dart'; 15 | import 'package:streamskit_mobile/features/app/bloc/app_bloc.dart'; 16 | 17 | void main(List args) async { 18 | await runZonedGuarded(() async { 19 | WidgetsFlutterBinding.ensureInitialized(); 20 | PaintingBinding.instance.imageCache.maximumSizeBytes = 21 | 1024 * 1024 * 300; // 300 MB 22 | 23 | await Application.initialAppLication(); 24 | 25 | await Firebase.initializeApp(); 26 | FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterError; 27 | runApp( 28 | MultiBlocProvider( 29 | providers: AppBloc.providers, 30 | child: const App(), 31 | ), 32 | ); 33 | }, (error, stackTrace) { 34 | FirebaseCrashlytics.instance.recordError(error, stackTrace); 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /ios/Runner/GoogleService-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CLIENT_ID 6 | 38681732543-a1c15bbp5qra3vdf4c26f8h4qj4mp8hm.apps.googleusercontent.com 7 | REVERSED_CLIENT_ID 8 | com.googleusercontent.apps.38681732543-a1c15bbp5qra3vdf4c26f8h4qj4mp8hm 9 | API_KEY 10 | AIzaSyBvr4N6_c5AtQfWH44EU8QHDH-sPgGtr9A 11 | GCM_SENDER_ID 12 | 38681732543 13 | PLIST_VERSION 14 | 1 15 | BUNDLE_ID 16 | com.streams.kit 17 | PROJECT_ID 18 | streamos-2c5cd 19 | STORAGE_BUCKET 20 | streamos-2c5cd.appspot.com 21 | IS_ADS_ENABLED 22 | 23 | IS_ANALYTICS_ENABLED 24 | 25 | IS_APPINVITE_ENABLED 26 | 27 | IS_GCM_ENABLED 28 | 29 | IS_SIGNIN_ENABLED 30 | 31 | GOOGLE_APP_ID 32 | 1:38681732543:ios:d0c2f5a9f52dd059a5ad0a 33 | 34 | -------------------------------------------------------------------------------- /.github/workflows/main.yaml: -------------------------------------------------------------------------------- 1 | name: Analyze, Build, Release apk to Firebase App Distribution 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | jobs: 9 | test: 10 | name: Analyze project 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v1 14 | - uses: actions/setup-java@v1 15 | with: 16 | java-version: "12.x" 17 | - uses: subosito/flutter-action@v1 18 | with: 19 | flutter-version: "3.3.3" 20 | - run: flutter pub get 21 | - run: flutter analyze 22 | 23 | build: 24 | needs: [test] 25 | name: Build APK 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: actions/checkout@v1 29 | - uses: actions/setup-java@v1 30 | with: 31 | java-version: "12.x" 32 | - uses: subosito/flutter-action@v1 33 | with: 34 | flutter-version: "3.3.3" 35 | - run: flutter pub get 36 | - run: flutter build apk --target-platform android-arm,android-arm64 --dart-define="lambiengcode=PRODUCTION" --release -v 37 | - name: Create a Release APK 38 | uses: ncipollo/release-action@v1 39 | with: 40 | artifacts: "build/app/outputs/apk/release/*.apk" 41 | token: ${{ secrets.TOKEN }} 42 | -------------------------------------------------------------------------------- /lib/core/util/custom_image/default_image.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/util/styles/style.dart'; 6 | 7 | // Project imports: 8 | 9 | class DefaultImage extends StatelessWidget { 10 | final double height; 11 | final double width; 12 | final EdgeInsetsGeometry? margin; 13 | final BoxShape shape; 14 | final BorderRadiusGeometry? borderRadius; 15 | final Widget? childInAvatar; 16 | const DefaultImage({ 17 | super.key, 18 | required this.height, 19 | required this.width, 20 | required this.margin, 21 | required this.shape, 22 | this.borderRadius, 23 | this.childInAvatar, 24 | }); 25 | @override 26 | Widget build(BuildContext context) { 27 | return Container( 28 | height: height, 29 | width: width, 30 | margin: margin, 31 | decoration: BoxDecoration( 32 | shape: shape, 33 | borderRadius: borderRadius, 34 | image: DecorationImage( 35 | image: const AssetImage( 36 | launcherIcon, 37 | ), 38 | fit: shape == BoxShape.circle ? BoxFit.fitHeight : BoxFit.contain, 39 | ), 40 | ), 41 | alignment: Alignment.bottomRight, 42 | child: childInAvatar, 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import file_selector_macos 9 | import firebase_auth 10 | import firebase_core 11 | import firebase_crashlytics 12 | import firebase_messaging 13 | import path_provider_foundation 14 | import sign_in_with_apple 15 | import sqflite 16 | import url_launcher_macos 17 | 18 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 19 | FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) 20 | FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) 21 | FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) 22 | FLTFirebaseCrashlyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCrashlyticsPlugin")) 23 | FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) 24 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 25 | SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin")) 26 | SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) 27 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 28 | } 29 | -------------------------------------------------------------------------------- /lib/features/home/data/datasources/local_live_stream_source.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:hive/hive.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | 5 | // Project imports: 6 | import 'package:streamskit_mobile/core/app/constant/storage_keys.dart'; 7 | import 'package:streamskit_mobile/features/home/data/model/live_stream_model.dart'; 8 | 9 | abstract class LocalLiveStreamSource { 10 | List getLiveStreams(); 11 | void saveLiveStreams(List liveStreams); 12 | void clearLiveStreams(); 13 | } 14 | 15 | @LazySingleton(as: LocalLiveStreamSource) 16 | class LocalLiveStreamSourceImpl implements LocalLiveStreamSource { 17 | final Box hiveBox = Hive.box(StorageKeys.boxLiveStreams); 18 | 19 | @override 20 | List getLiveStreams() { 21 | List liveStreamsRaw = hiveBox.get(StorageKeys.liveStreamsKey) ?? []; 22 | return liveStreamsRaw 23 | .map((liveStream) => LiveStreamModel.fromJson(liveStream)) 24 | .toList(); 25 | } 26 | 27 | @override 28 | void saveLiveStreams(List liveStreams) { 29 | hiveBox.put( 30 | StorageKeys.liveStreamsKey, 31 | liveStreams.map((liveStream) => liveStream.toJson()).toList(), 32 | ); 33 | } 34 | 35 | @override 36 | void clearLiveStreams() { 37 | hiveBox.delete(StorageKeys.liveStreamsKey); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/core/util/common/touchable_opacity.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | class TouchableOpacity extends StatefulWidget { 5 | final Function? onTap; 6 | final Function? onLongPress; 7 | final Widget child; 8 | 9 | const TouchableOpacity({ 10 | super.key, 11 | required this.child, 12 | this.onTap, 13 | this.onLongPress, 14 | }); 15 | 16 | @override 17 | State createState() => _TouchableOpacityState(); 18 | } 19 | 20 | class _TouchableOpacityState extends State { 21 | bool enable = false; 22 | @override 23 | Widget build(BuildContext context) { 24 | return GestureDetector( 25 | onLongPress: () { 26 | if (!enable && widget.onLongPress != null) { 27 | widget.onLongPress!(); 28 | } 29 | }, 30 | onTap: () { 31 | if (!enable && widget.onTap != null) { 32 | widget.onTap!(); 33 | } 34 | }, 35 | onTapDown: (a) { 36 | setState(() { 37 | enable = true; 38 | }); 39 | }, 40 | onTapUp: (a) { 41 | setState(() { 42 | enable = false; 43 | }); 44 | }, 45 | onTapCancel: () { 46 | setState(() { 47 | enable = false; 48 | }); 49 | }, 50 | child: Opacity(opacity: enable ? 0.5 : 1, child: widget.child), 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/features/search/data/top_search_model.dart: -------------------------------------------------------------------------------- 1 | // Dart imports: 2 | import 'dart:convert'; 3 | 4 | class TopSearch { 5 | String nameStreamer; 6 | int stt; 7 | TopSearch({ 8 | required this.nameStreamer, 9 | required this.stt, 10 | }); 11 | 12 | TopSearch copyWith({ 13 | String? nameStreamer, 14 | int? stt, 15 | }) { 16 | return TopSearch( 17 | nameStreamer: nameStreamer ?? this.nameStreamer, 18 | stt: stt ?? this.stt, 19 | ); 20 | } 21 | 22 | Map toMap() { 23 | return { 24 | 'nameStreamer': nameStreamer, 25 | 'stt': stt, 26 | }; 27 | } 28 | 29 | factory TopSearch.fromMap(Map map) { 30 | return TopSearch( 31 | nameStreamer: map['nameStreamer'] ?? '', 32 | stt: map['stt']?.toInt() ?? 0, 33 | ); 34 | } 35 | 36 | String toJson() => json.encode(toMap()); 37 | 38 | factory TopSearch.fromJson(String source) => 39 | TopSearch.fromMap(json.decode(source)); 40 | 41 | @override 42 | String toString() => 'TopSearch(nameStreamer: $nameStreamer, stt: $stt)'; 43 | 44 | @override 45 | bool operator ==(Object other) { 46 | if (identical(this, other)) return true; 47 | 48 | return other is TopSearch && 49 | other.nameStreamer == nameStreamer && 50 | other.stt == stt; 51 | } 52 | 53 | @override 54 | int get hashCode => nameStreamer.hashCode ^ stt.hashCode; 55 | } 56 | -------------------------------------------------------------------------------- /windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(10, 10); 29 | Win32Window::Size size(1280, 720); 30 | if (!window.CreateAndShow(L"streamskit_mobile", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | window.SetQuitOnClose(true); 34 | 35 | ::MSG msg; 36 | while (::GetMessage(&msg, nullptr, 0, 0)) { 37 | ::TranslateMessage(&msg); 38 | ::DispatchMessage(&msg); 39 | } 40 | 41 | ::CoUninitialize(); 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.11' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/widgets/gribview_live_card.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 6 | import 'package:streamskit_mobile/features/profile/data/live_card_model.dart'; 7 | import 'package:streamskit_mobile/features/profile/presentation/widgets/live_card_profile.dart'; 8 | 9 | class GridviewLiveCard extends StatelessWidget { 10 | final List liveModel; 11 | final int type; 12 | final ScrollPhysics? physics; 13 | final bool shrinkWrap; 14 | final EdgeInsetsGeometry? padding; 15 | const GridviewLiveCard({ 16 | super.key, 17 | required this.liveModel, 18 | required this.type, 19 | this.physics, 20 | this.shrinkWrap = true, 21 | this.padding, 22 | }); 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return Padding( 27 | padding: padding ?? EdgeInsets.symmetric(horizontal: 16.sp), 28 | child: GridView.count( 29 | shrinkWrap: shrinkWrap, 30 | padding: EdgeInsets.only(top: 8.sp, bottom: 72.sp), 31 | crossAxisCount: 2, 32 | crossAxisSpacing: 15.sp, 33 | childAspectRatio: 0.7, 34 | physics: physics ?? const NeverScrollableScrollPhysics(), 35 | mainAxisSpacing: 20.sp, 36 | children: List.generate( 37 | liveModel.length, 38 | (index) => LiveCardProflie(liveModel: liveModel[index]), 39 | ), 40 | ), 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /lib/features/chat/presentation/widgets/button_option_widget.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/navigator/app_pages.dart'; 6 | import 'package:streamskit_mobile/core/util/common/touchable_opacity.dart'; 7 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 8 | 9 | class ButtonOptionWidget extends StatelessWidget { 10 | final String text; 11 | final Function handlePressed; 12 | final bool isDanger; 13 | final bool isCancel; 14 | const ButtonOptionWidget({ 15 | super.key, 16 | required this.text, 17 | required this.handlePressed, 18 | this.isDanger = false, 19 | this.isCancel = false, 20 | }); 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return TouchableOpacity( 25 | onTap: () { 26 | AppNavigator.pop(); 27 | handlePressed(); 28 | }, 29 | child: Container( 30 | height: 42.sp, 31 | alignment: Alignment.center, 32 | color: Colors.transparent, 33 | child: Text( 34 | text, 35 | style: TextStyle( 36 | color: isDanger 37 | ? Theme.of(context).brightness == Brightness.dark 38 | ? const Color(0xffdb5757) 39 | : Colors.red.shade700 40 | : Colors.white, //Theme.of(context).textTheme.bodyText2!.color, 41 | fontSize: 13.sp, 42 | fontWeight: isCancel ? FontWeight.w700 : FontWeight.w600, 43 | ), 44 | ), 45 | ), 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/features/search/presentation/widgets/search_more_widget.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/app/colors/app_color.dart'; 6 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 7 | import 'package:streamskit_mobile/core/util/styles/profile_style.dart'; 8 | 9 | class SearchMoreWidget extends StatelessWidget { 10 | final String nameStreamer; 11 | final String stt; 12 | final Color sttColor; 13 | const SearchMoreWidget({ 14 | super.key, 15 | required this.nameStreamer, 16 | required this.stt, 17 | required this.sttColor, 18 | }); 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return Row( 23 | children: [ 24 | Container( 25 | width: 15.sp, 26 | decoration: BoxDecoration( 27 | gradient: LinearGradient( 28 | colors: [sttColor.withOpacity(0.6), sttColor], 29 | stops: const [0.0, 1.0], 30 | begin: Alignment.topCenter, 31 | end: Alignment.bottomCenter, 32 | ), 33 | shape: BoxShape.circle, 34 | border: Border.all( 35 | width: 0.5, 36 | color: mCL, 37 | ), 38 | ), 39 | child: Align( 40 | alignment: Alignment.center, child: Text(stt, style: text9mCL)), 41 | ), 42 | SizedBox( 43 | width: 8.sp, 44 | ), 45 | Text( 46 | nameStreamer, 47 | style: text11mCL, 48 | ), 49 | ], 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '13.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | target.build_configurations.each do |config| 41 | config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0' 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/widgets/edit_profile_widget.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/util/common/touchable_opacity.dart'; 6 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 7 | import 'package:streamskit_mobile/core/util/styles/profile_style.dart'; 8 | 9 | class ProfileEditWidget extends StatelessWidget { 10 | final String title; 11 | final String value; 12 | final Function()? onTap; 13 | final TextStyle? style; 14 | const ProfileEditWidget({ 15 | super.key, 16 | required this.title, 17 | required this.value, 18 | this.style, 19 | this.onTap, 20 | }); 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return TouchableOpacity( 25 | onTap: onTap ?? () {}, 26 | child: Container( 27 | padding: EdgeInsets.symmetric(horizontal: 8.sp, vertical: 12.sp), 28 | decoration: BoxDecoration( 29 | color: Colors.grey.shade900, 30 | ), 31 | child: Row( 32 | children: [ 33 | Padding( 34 | padding: EdgeInsets.only(left: 8.sp), 35 | child: Text( 36 | title, 37 | style: text11mGB, 38 | ), 39 | ), 40 | const Spacer(), 41 | Container( 42 | constraints: BoxConstraints(maxWidth: 150.sp), 43 | child: Text( 44 | value, 45 | style: style ?? text11mCL, 46 | ), 47 | ), 48 | ], 49 | ), 50 | ), 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/widgets/sign_in_button.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 6 | 7 | class SignInButton extends StatelessWidget { 8 | final String title; 9 | final String iconAsset; 10 | final Function() onPressed; 11 | 12 | const SignInButton({ 13 | super.key, 14 | required this.iconAsset, 15 | required this.title, 16 | required this.onPressed, 17 | }); 18 | @override 19 | Widget build(BuildContext context) { 20 | return GestureDetector( 21 | onTap: onPressed, 22 | child: Container( 23 | decoration: BoxDecoration( 24 | borderRadius: BorderRadius.circular(30.sp), 25 | color: Colors.white, 26 | ), 27 | padding: EdgeInsets.symmetric(vertical: 11.25.sp), 28 | child: Row( 29 | crossAxisAlignment: CrossAxisAlignment.center, 30 | mainAxisAlignment: MainAxisAlignment.start, 31 | children: [ 32 | SizedBox(width: 14.5.w), 33 | Image.asset( 34 | iconAsset, 35 | height: 16.sp, 36 | width: 16.sp, 37 | fit: BoxFit.contain, 38 | ), 39 | SizedBox(width: 10.sp), 40 | Text( 41 | title, 42 | style: TextStyle( 43 | color: Theme.of(context).scaffoldBackgroundColor, 44 | fontWeight: FontWeight.w700, 45 | fontSize: 11.5.sp, 46 | ), 47 | ), 48 | ], 49 | ), 50 | ), 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/features/home/presentation/widgets/list_live_stream.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 6 | import 'package:streamskit_mobile/features/home/data/model/live_stream_model.dart'; 7 | import 'package:streamskit_mobile/features/home/presentation/widgets/live_stream_card.dart'; 8 | import 'package:streamskit_mobile/features/stream/presentation/screens/stream_screen.dart'; 9 | 10 | class ListLiveStream extends StatelessWidget { 11 | const ListLiveStream({super.key}); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Expanded( 16 | child: GridView.builder( 17 | padding: EdgeInsets.symmetric( 18 | horizontal: 16.sp, 19 | ).add( 20 | EdgeInsets.only( 21 | bottom: 80.sp, 22 | ), 23 | ), 24 | physics: const BouncingScrollPhysics(), 25 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 26 | crossAxisCount: 0.itemCountGridViewCalendar, 27 | mainAxisSpacing: 18.sp, 28 | crossAxisSpacing: 10.sp, 29 | childAspectRatio: 0.58, 30 | ), 31 | itemCount: listLiveStreamFake.length, 32 | itemBuilder: (context, index) { 33 | return LiveStreamCard( 34 | liveStreamModel: listLiveStreamFake[index], 35 | onTap: (() { 36 | Navigator.of(context).push(MaterialPageRoute( 37 | builder: (context) => const StreamScreen())); 38 | }), 39 | ); 40 | }, 41 | ), 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/core/app/themes/box_shadow.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/app/colors/app_color.dart'; 6 | 7 | class BoxShadowStatic { 8 | static List? boxShadow(BuildContext context) { 9 | if (Theme.of(context).brightness == Brightness.dark) { 10 | return [ 11 | BoxShadow( 12 | color: const Color(0xFF14171A).withOpacity(.65), 13 | offset: const Offset(.75, .75), 14 | blurRadius: .4, 15 | ), 16 | BoxShadow( 17 | color: colorBlack.withOpacity(.25), 18 | offset: const Offset(-.4, -.4), 19 | blurRadius: .4, 20 | ), 21 | ]; 22 | } else { 23 | return [ 24 | BoxShadow( 25 | color: Colors.black.withOpacity(0.08), 26 | blurRadius: 4, 27 | offset: const Offset(1, 1), 28 | ), 29 | ]; 30 | } 31 | } 32 | 33 | static List? boxShadowActive(BuildContext context) { 34 | if (Theme.of(context).brightness == Brightness.dark) { 35 | return [ 36 | BoxShadow( 37 | color: Colors.black.withOpacity(.8), 38 | offset: const Offset(1, 1), 39 | blurRadius: 1, 40 | ), 41 | BoxShadow( 42 | color: colorBlack.withOpacity(.35), 43 | offset: const Offset(-1, -1), 44 | blurRadius: 1, 45 | ), 46 | ]; 47 | } else { 48 | return [ 49 | BoxShadow( 50 | color: Colors.black.withOpacity(0.08), 51 | blurRadius: 4, 52 | offset: const Offset(1, 1), 53 | ), 54 | ]; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/core/navigator/app_navigator_observer.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | class AppNavigatorObserver extends NavigatorObserver { 5 | static List routeNames = []; 6 | 7 | @override 8 | void didPush(Route route, Route? previousRoute) { 9 | super.didPush(route, previousRoute); 10 | routeNames.add(route.settings.name); 11 | 12 | updateCurrentRouteToBloc(route.settings.name ?? ''); 13 | } 14 | 15 | @override 16 | void didPop(Route route, Route? previousRoute) { 17 | super.didPop(route, previousRoute); 18 | if (routeNames.length > 1) { 19 | routeNames.removeLast(); 20 | } 21 | 22 | updateCurrentRouteToBloc(route.settings.name ?? ''); 23 | } 24 | 25 | @override 26 | void didReplace({Route? newRoute, Route? oldRoute}) { 27 | super.didReplace(); 28 | routeNames[routeNames.length - 1] = newRoute?.settings.name ?? ''; 29 | 30 | updateCurrentRouteToBloc(newRoute?.settings.name ?? ''); 31 | } 32 | 33 | @override 34 | void didRemove(Route route, Route? previousRoute) { 35 | super.didRemove(route, previousRoute); 36 | int indexOfRoute = routeNames.indexOf(route.settings.name ?? ''); 37 | if (indexOfRoute != -1) { 38 | routeNames.removeRange(indexOfRoute, routeNames.length); 39 | } 40 | 41 | updateCurrentRouteToBloc(route.settings.name ?? ''); 42 | } 43 | 44 | void updateCurrentRouteToBloc(String routeName) {} 45 | 46 | // Static 47 | static String? get currentRouteName => 48 | routeNames.lastWhere((route) => route != null && route.isNotEmpty, 49 | orElse: () => null); 50 | 51 | static void resetRoutes() { 52 | routeNames = []; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /test/features/home/domain/usecases/get_list_live_stream_test.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:dartz/dartz.dart'; 3 | import 'package:flutter_test/flutter_test.dart'; 4 | import 'package:mockito/annotations.dart'; 5 | import 'package:mockito/mockito.dart'; 6 | 7 | // Project imports: 8 | import 'package:streamskit_mobile/core/error/failure.dart'; 9 | import 'package:streamskit_mobile/core/usecase/usecase.dart'; 10 | import 'package:streamskit_mobile/features/home/data/model/live_stream_model.dart'; 11 | import 'package:streamskit_mobile/features/home/domain/repositories/live_stream_repository.dart'; 12 | import 'package:streamskit_mobile/features/home/domain/usecases/get_list_live_streaming.dart'; 13 | import 'get_list_live_stream_test.mocks.dart'; 14 | 15 | @GenerateNiceMocks([MockSpec()]) 16 | List liveStreams = listLiveStreamFake; 17 | 18 | void main() { 19 | late GetListLiveStreaming usecase; 20 | late MockLiveStreamRepository mockLiveStreamRepository; 21 | 22 | setUp(() { 23 | mockLiveStreamRepository = MockLiveStreamRepository(); 24 | usecase = GetListLiveStreaming(repository: mockLiveStreamRepository); 25 | }); 26 | 27 | test( 28 | 'should get list live streams from repository', 29 | () async { 30 | when(mockLiveStreamRepository.getLiveStreams()) 31 | .thenAnswer((_) => Right(liveStreams)); 32 | // act 33 | final result = usecase(NoParams()); 34 | // assert 35 | expect(result.isRight(), 36 | Right>(liveStreams).isRight()); 37 | verify(mockLiveStreamRepository.getLiveStreams()); 38 | verifyNoMoreInteractions(mockLiveStreamRepository); 39 | }, 40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /lib/features/home/data/model/category_model.dart: -------------------------------------------------------------------------------- 1 | // Dart imports: 2 | import 'dart:convert'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/util/styles/style.dart'; 6 | 7 | class CategoryModel { 8 | String title; 9 | String image; 10 | CategoryModel({ 11 | required this.title, 12 | required this.image, 13 | }); 14 | 15 | CategoryModel copyWith({ 16 | String? title, 17 | String? image, 18 | }) { 19 | return CategoryModel( 20 | title: title ?? this.title, 21 | image: image ?? this.image, 22 | ); 23 | } 24 | 25 | Map toMap() { 26 | return { 27 | 'title': title, 28 | 'image': image, 29 | }; 30 | } 31 | 32 | factory CategoryModel.fromMap(Map map) { 33 | return CategoryModel( 34 | title: map['title'] ?? '', 35 | image: map['image'] ?? '', 36 | ); 37 | } 38 | 39 | String toJson() => json.encode(toMap()); 40 | 41 | factory CategoryModel.fromJson(String source) => 42 | CategoryModel.fromMap(json.decode(source)); 43 | 44 | @override 45 | String toString() => 'CategoryModel(title: $title, image: $image)'; 46 | 47 | @override 48 | bool operator ==(Object other) { 49 | if (identical(this, other)) return true; 50 | 51 | return other is CategoryModel && 52 | other.title == title && 53 | other.image == image; 54 | } 55 | 56 | @override 57 | int get hashCode => title.hashCode ^ image.hashCode; 58 | } 59 | 60 | List listCategoryFake = [ 61 | CategoryModel(title: 'Popular', image: iconFire), 62 | CategoryModel(title: 'Nearby', image: iconNearby), 63 | CategoryModel(title: 'Games', image: iconGame), 64 | CategoryModel(title: 'Sharing', image: iconSharing), 65 | ]; 66 | -------------------------------------------------------------------------------- /lib/core/util/numeral/parser.dart: -------------------------------------------------------------------------------- 1 | /// Numeral parsed value. 2 | class NumeralParsedValue { 3 | /// String suffix. 4 | final String suffix; 5 | 6 | /// number parsed value. 7 | final num value; 8 | 9 | /// Create the [NumeralParsedValue] 10 | /// 11 | /// [value] Is the parsed value. 12 | /// [suffix] The last string after the connection. 13 | NumeralParsedValue._(this.value, this.suffix); 14 | 15 | /// [NumeralParsedValue] Factory. 16 | /// 17 | /// [value] Is the parsed value. 18 | /// [suffix] The last string after the connection. 19 | factory NumeralParsedValue({ 20 | required String suffix, 21 | required num value, 22 | }) { 23 | return NumeralParsedValue._(value, suffix); 24 | } 25 | 26 | /// To display string. 27 | @override 28 | String toString() { 29 | return '$runtimeType(String suffix = "$suffix", num value = $value);'; 30 | } 31 | } 32 | 33 | /// Numeral value parser. 34 | /// 35 | /// [value] Is need parse value. 36 | /// 37 | /// return a [NumeralParsedValue]. 38 | NumeralParsedValue numeralParser(num value) { 39 | final num abs = value.abs(); 40 | 41 | // If number > 1 trillion. 42 | if (abs >= 1000000000000) { 43 | return NumeralParsedValue(value: value / 1000000000000, suffix: 'T'); 44 | 45 | // If number > 1 billion. 46 | } else if (abs >= 1000000000) { 47 | return NumeralParsedValue(value: value / 1000000000, suffix: 'B'); 48 | 49 | // If number > 1 million. 50 | } else if (abs >= 1000000) { 51 | return NumeralParsedValue(value: value / 1000000, suffix: 'M'); 52 | 53 | // If number > 1 thousand. 54 | } else if (abs >= 1000) { 55 | return NumeralParsedValue(value: value / 1000, suffix: 'K'); 56 | } 57 | 58 | return NumeralParsedValue(value: value, suffix: ''); 59 | } 60 | -------------------------------------------------------------------------------- /lib/features/auth/data/repositories/auth_repository_impl.dart: -------------------------------------------------------------------------------- 1 | // Package imports: 2 | import 'package:dartz/dartz.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | 5 | // Project imports: 6 | import 'package:streamskit_mobile/core/error/failure.dart'; 7 | import 'package:streamskit_mobile/core/usecase/usecase.dart'; 8 | import 'package:streamskit_mobile/features/auth/data/datasources/auth_local_datasource.dart'; 9 | import 'package:streamskit_mobile/features/auth/data/datasources/auth_remote_datasource.dart'; 10 | import 'package:streamskit_mobile/features/auth/domain/entities/social.dart'; 11 | import 'package:streamskit_mobile/features/auth/domain/repositories/auth_repository.dart'; 12 | 13 | @LazySingleton(as: AuthRepository) 14 | class AuthRepositoryImpl implements AuthRepository { 15 | final AuthLocalDataSource localData; 16 | final AuthRemoteDataSource remoteData; 17 | 18 | const AuthRepositoryImpl({ 19 | required this.localData, 20 | required this.remoteData, 21 | }); 22 | 23 | @override 24 | Either checkSignined() { 25 | String? token = localData.getAccessToken(); 26 | 27 | if (token == null) { 28 | return Left(NullValue()); 29 | } 30 | 31 | return const Right(true); 32 | } 33 | 34 | @override 35 | Future> signIn(Params params) async { 36 | String? accessToken = await remoteData.signInWithSocial( 37 | params.object as SocialValue, 38 | ); 39 | 40 | if (accessToken != null) { 41 | localData.saveAccessToken(accessToken); 42 | return const Right(true); 43 | } 44 | 45 | return const Right(false); 46 | } 47 | 48 | @override 49 | Either signOut() { 50 | localData.clearAccessToken(); 51 | return const Right(true); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/core/types/http_status_code.dart: -------------------------------------------------------------------------------- 1 | class StatusCode { 2 | static const int continueCode = 100; 3 | static const int switchingProtocols = 101; 4 | static const int ok = 200; 5 | static const int created = 201; 6 | static const int accepted = 202; 7 | static const int notiAuthoritativeInfomation = 203; 8 | static const int noContent = 204; 9 | static const int resetContent = 205; 10 | static const int partialContent = 206; 11 | static const int multipleChoices = 300; 12 | static const int movedPermanently = 301; 13 | static const int found = 302; 14 | static const int seeOther = 303; 15 | static const int notModified = 304; 16 | static const int useProxy = 305; 17 | static const int temporaryRedirect = 307; 18 | static const int badRequest = 400; 19 | static const int unauthorized = 401; 20 | static const int paymentRequired = 402; 21 | static const int forbiden = 403; 22 | static const int notFound = 404; 23 | static const int methodNotAllowed = 405; 24 | static const int notAcceptable = 406; 25 | static const int proxyAuthenticationRequired = 407; 26 | static const int requestTimeout = 408; 27 | static const int conflict = 409; 28 | static const int gone = 410; 29 | static const int lengthRequired = 411; 30 | static const int preconditionFailed = 412; 31 | static const int requestEntityTooLarge = 413; 32 | static const int requestUriTooLong = 414; 33 | static const int unsupportedMediaType = 415; 34 | static const int requestedRangeNotSatisfiable = 416; 35 | static const int expectationFailed = 417; 36 | static const int internalServerError = 500; 37 | static const int notImplemented = 501; 38 | static const int badGateway = 502; 39 | 40 | static List get validateStatus => 41 | [unauthorized, notFound, internalServerError, badGateway]; 42 | } 43 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled. 5 | 6 | version: 7 | revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 8 | channel: stable 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 17 | base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 18 | - platform: android 19 | create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 20 | base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 21 | - platform: ios 22 | create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 23 | base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 24 | - platform: linux 25 | create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 26 | base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 27 | - platform: macos 28 | create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 29 | base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 30 | - platform: web 31 | create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 32 | base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 33 | - platform: windows 34 | create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 35 | base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /test/features/home/data/repositories/live_stream_repository_test.dart: -------------------------------------------------------------------------------- 1 | // Dart imports: 2 | import 'dart:convert'; 3 | 4 | // Package imports: 5 | import 'package:flutter_test/flutter_test.dart'; 6 | import 'package:mockito/mockito.dart'; 7 | 8 | // Project imports: 9 | import 'package:streamskit_mobile/features/home/data/datasources/local_live_stream_source.dart'; 10 | import 'package:streamskit_mobile/features/home/data/model/live_stream_model.dart'; 11 | import 'package:streamskit_mobile/features/home/data/repositories/live_stream_repository_impl.dart'; 12 | import '../../../../fixtures/fixture_reader.dart'; 13 | 14 | class MockLocalDataSource extends Mock implements LocalLiveStreamSource { 15 | @override 16 | List getLiveStreams() { 17 | return super.noSuchMethod(Invocation.method(#getLiveStreams, [])) ?? []; 18 | } 19 | } 20 | 21 | void main() { 22 | late LiveStreamRepositoryImpl repository; 23 | late MockLocalDataSource mockLocalDataSource; 24 | 25 | setUp(() { 26 | mockLocalDataSource = MockLocalDataSource(); 27 | repository = LiveStreamRepositoryImpl(localData: mockLocalDataSource); 28 | }); 29 | 30 | group('get live streams', () { 31 | final List arrayRaw = 32 | jsonDecode(fixture('live_stream_model.json')); 33 | final List liveStreams = arrayRaw 34 | .map( 35 | (liveStream) => LiveStreamModel.fromMap(liveStream), 36 | ) 37 | .toList(); 38 | 39 | test( 40 | 'should return list live stream model', 41 | () async { 42 | // arrange 43 | when(mockLocalDataSource.getLiveStreams()).thenAnswer( 44 | (_) => liveStreams, 45 | ); 46 | // act 47 | repository.getLiveStreams(); 48 | // assert 49 | verifyNever(mockLocalDataSource.saveLiveStreams(liveStreams)); 50 | }, 51 | ); 52 | }); 53 | } 54 | -------------------------------------------------------------------------------- /windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} WIN32 10 | "flutter_window.cpp" 11 | "main.cpp" 12 | "utils.cpp" 13 | "win32_window.cpp" 14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 15 | "Runner.rc" 16 | "runner.exe.manifest" 17 | ) 18 | 19 | # Apply the standard set of build settings. This can be removed for applications 20 | # that need different build settings. 21 | apply_standard_settings(${BINARY_NAME}) 22 | 23 | # Add preprocessor definitions for the build version. 24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 29 | 30 | # Disable Windows macros that collide with C++ standard library functions. 31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 32 | 33 | # Add dependency libraries and include directories. Add any application-specific 34 | # dependencies here. 35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 36 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 37 | 38 | # Run the Flutter tool portions of the build. This must not be removed. 39 | add_dependencies(${BINARY_NAME} flutter_assemble) 40 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/widgets/login_setting.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Package imports: 5 | import 'package:flutter_phosphor_icons/flutter_phosphor_icons.dart'; 6 | 7 | // Project imports: 8 | import 'package:streamskit_mobile/core/app/colors/app_color.dart'; 9 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 10 | import 'package:streamskit_mobile/features/app/bloc/app_bloc.dart'; 11 | import 'package:streamskit_mobile/features/auth/presentation/bloc/auth_bloc.dart'; 12 | import 'package:streamskit_mobile/features/profile/presentation/widgets/row_icon_text.dart'; 13 | 14 | class LoginSetting extends StatelessWidget { 15 | const LoginSetting({ 16 | super.key, 17 | }); 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return Column( 22 | crossAxisAlignment: CrossAxisAlignment.start, 23 | children: [ 24 | Text( 25 | "LOGIN", 26 | style: TextStyle( 27 | fontSize: 10.sp, 28 | color: Colors.grey, 29 | fontWeight: FontWeight.w700, 30 | ), 31 | ), 32 | SizedBox(height: 8.sp), 33 | RowIconText( 34 | title: "Switch account", 35 | colorLeading: mCL, 36 | sizeLeading: 15.sp, 37 | textStyle: TextStyle(color: mCL, fontSize: 11.sp), 38 | iconLeading: PhosphorIcons.user_switch_thin, 39 | onTap: () {}, 40 | ), 41 | SizedBox(height: 8.sp), 42 | RowIconText( 43 | title: "Log out", 44 | colorLeading: mCL, 45 | sizeLeading: 15.sp, 46 | textStyle: TextStyle(color: mCL, fontSize: 11.sp), 47 | iconLeading: PhosphorIcons.sign_out, 48 | onTap: () { 49 | AppBloc.authBloc.add(SignOutEvent()); 50 | }, 51 | ), 52 | ], 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/core/util/numeral/numeral.dart: -------------------------------------------------------------------------------- 1 | // Project imports: 2 | import 'parser.dart'; 3 | 4 | /// Default fraction digits value. 5 | const int defaultFractionDigits = 1; 6 | 7 | /// Numeral formatter 8 | /// 9 | /// This class is used to format numbers into strings. 10 | /// 11 | /// Example usage: 12 | /// ```dart 13 | /// const numeral = Numeral(1314); 14 | /// print(numeral.format()); // => "1.314K" 15 | /// ``` 16 | class Numeral { 17 | /// Create [Numeral] class. 18 | /// 19 | /// The Factory create a [Numeral] class instance. 20 | /// 21 | /// [numeral] is num [Type]. 22 | /// 23 | /// return [Numeral] instance. 24 | const Numeral(this.numeral); 25 | 26 | /// Original numeral. 27 | final num numeral; 28 | 29 | /// Format [number] to beautiful [String]. 30 | /// 31 | /// E.g: 32 | /// ```dart 33 | /// Numeral(1000).value(); // -> 1K 34 | /// ``` 35 | /// 36 | /// return a [String] type. 37 | String format({int fractionDigits = defaultFractionDigits}) { 38 | final NumeralParsedValue parsed = numeralParser(numeral); 39 | 40 | return _removeEndsZero(parsed.value.toStringAsFixed(fractionDigits)) + 41 | parsed.suffix; 42 | } 43 | 44 | /// Remove value ends with zero. 45 | /// 46 | /// Remove formated value ends with zero, 47 | /// replace to zero string. 48 | /// 49 | /// [value] type is [String]. 50 | /// 51 | /// return a [String] type. 52 | String _removeEndsZero(String value) { 53 | if (!value.contains('.')) { 54 | return value; 55 | } 56 | 57 | if (value.endsWith('.')) { 58 | return value.substring(0, value.length - 1); 59 | } else if (value.endsWith('0')) { 60 | return _removeEndsZero(value.substring(0, value.length - 1)); 61 | } 62 | 63 | return value; 64 | } 65 | 66 | /// Get formated value. 67 | /// 68 | /// Get the [value] function value. 69 | /// 70 | /// return a [String] type. 71 | @override 72 | String toString() => format(); 73 | } 74 | -------------------------------------------------------------------------------- /lib/core/util/sizer_custom/extension.dart: -------------------------------------------------------------------------------- 1 | part of 'sizer.dart'; 2 | 3 | extension SizerExt on num { 4 | /// Calculates the height depending on the device's screen size 5 | /// 6 | /// Eg: 20.h -> will take 20% of the screen's height 7 | double get h => this * SizerUtil.height / 100; 8 | 9 | /// Calculates the width depending on the device's screen size 10 | /// 11 | /// Eg: 20.w -> will take 20% of the screen's width 12 | double get w => this * SizerUtil.width / 100; 13 | 14 | /// Calculates the sp (Scalable Pixel) depending on the device's screen size 15 | // double get sp => this * (SizerUtil.width / 3) / 100; 16 | 17 | double get width { 18 | // DEVICE INCH 19 | double deviceSize = math.sqrt(100.h * 100.h + 100.w * 100.w) / inchToDP; 20 | if (deviceSize > 6.5) { 21 | return 65.w * (6.5 / deviceSize); 22 | } else if (deviceSize > 5.5) { 23 | return 100.w; 24 | } else if (deviceSize > 5.0) { 25 | return 90.w; 26 | } else { 27 | return 85.w; 28 | } 29 | } 30 | 31 | bool get isTablet { 32 | // DEVICE INCH 33 | double deviceSize = math.sqrt(100.h * 100.h + 100.w * 100.w) / inchToDP; 34 | if (deviceSize > 6.5) { 35 | return true; 36 | } 37 | 38 | return false; 39 | } 40 | 41 | double get sp => this * (width / 3) / 100; 42 | 43 | int get itemCountGridViewCalendar { 44 | return (100.w / (150.sp)).round(); 45 | } 46 | 47 | int get itemCountGridViewMoney { 48 | return (65.w / (100.sp)).round(); 49 | } 50 | 51 | int get itemCountGridViewPhoto { 52 | // DEVICE INCH 53 | double deviceSize = math.sqrt(100.h * 100.h + 100.w * 100.w) / inchToDP; 54 | if (deviceSize > 7.5) { 55 | return 5; 56 | } else if (deviceSize > 6) { 57 | return 4; 58 | } else if (deviceSize > 5.5) { 59 | return 3; 60 | } else { 61 | return 3; 62 | } 63 | } 64 | 65 | double get heightDialogListTablet { 66 | return 52.h; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr); 51 | std::string utf8_string; 52 | if (target_length == 0 || target_length > utf8_string.max_size()) { 53 | return utf8_string; 54 | } 55 | utf8_string.resize(target_length); 56 | int converted_length = ::WideCharToMultiByte( 57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 58 | -1, utf8_string.data(), 59 | target_length, nullptr, nullptr); 60 | if (converted_length == 0) { 61 | return std::string(); 62 | } 63 | return utf8_string; 64 | } 65 | -------------------------------------------------------------------------------- /lib/features/profile/data/list_live_card_model.dart: -------------------------------------------------------------------------------- 1 | // Dart imports: 2 | import 'dart:convert'; 3 | 4 | // Flutter imports: 5 | import 'package:flutter/foundation.dart'; 6 | 7 | // Project imports: 8 | import 'package:streamskit_mobile/features/profile/data/live_card_model.dart'; 9 | 10 | class ListLiveCardModel { 11 | final int type; // 1: Live Stream // 2: LastLive // 3: STar // 4 Posts 12 | final List listLiveCardModel; 13 | ListLiveCardModel({ 14 | required this.type, 15 | required this.listLiveCardModel, 16 | }); 17 | 18 | ListLiveCardModel copyWith({ 19 | int? type, 20 | List? listLiveCardModel, 21 | }) { 22 | return ListLiveCardModel( 23 | type: type ?? this.type, 24 | listLiveCardModel: listLiveCardModel ?? this.listLiveCardModel, 25 | ); 26 | } 27 | 28 | Map toMap() { 29 | return { 30 | 'type': type, 31 | 'listLiveCardModel': listLiveCardModel.map((x) => x.toMap()).toList(), 32 | }; 33 | } 34 | 35 | factory ListLiveCardModel.fromMap(Map map) { 36 | return ListLiveCardModel( 37 | type: map['type']?.toInt() ?? 0, 38 | listLiveCardModel: List.from( 39 | map['listLiveCardModel']?.map((x) => LiveCardModel.fromMap(x))), 40 | ); 41 | } 42 | 43 | String toJson() => json.encode(toMap()); 44 | 45 | factory ListLiveCardModel.fromJson(String source) => 46 | ListLiveCardModel.fromMap(json.decode(source)); 47 | 48 | @override 49 | String toString() => 50 | 'ListLiveCardModel(type: $type, listLiveCardModel: $listLiveCardModel)'; 51 | 52 | @override 53 | bool operator ==(Object other) { 54 | if (identical(this, other)) return true; 55 | 56 | return other is ListLiveCardModel && 57 | other.type == type && 58 | listEquals(other.listLiveCardModel, listLiveCardModel); 59 | } 60 | 61 | @override 62 | int get hashCode => type.hashCode ^ listLiveCardModel.hashCode; 63 | } 64 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/widgets/bottom_sheet_gender.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/app/colors/app_color.dart'; 6 | import 'package:streamskit_mobile/core/navigator/app_pages.dart'; 7 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 8 | import 'package:streamskit_mobile/features/profile/presentation/widgets/bottom_sheet_choose_option.dart'; 9 | import 'package:streamskit_mobile/features/profile/presentation/widgets/row_icon_text.dart'; 10 | 11 | class BottomSheetGender extends StatelessWidget { 12 | final Function handleSelectGender; 13 | const BottomSheetGender({super.key, required this.handleSelectGender}); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Container( 18 | padding: EdgeInsets.symmetric(horizontal: 16.sp).add( 19 | EdgeInsets.only(bottom: 10.sp), 20 | ), 21 | decoration: BoxDecoration( 22 | borderRadius: BorderRadius.vertical( 23 | top: Radius.circular(20.sp), 24 | ), 25 | color: Colors.grey.shade900, 26 | ), 27 | child: Column( 28 | mainAxisSize: MainAxisSize.min, 29 | crossAxisAlignment: CrossAxisAlignment.center, 30 | children: [ 31 | const DividerBottomSheet(), 32 | SizedBox( 33 | height: 8.sp, 34 | ), 35 | RowIconText( 36 | title: "Man", 37 | onTap: () { 38 | AppNavigator.pop(); 39 | handleSelectGender("Man"); 40 | }, 41 | ), 42 | Divider( 43 | thickness: 0.2, 44 | color: mCU, 45 | ), 46 | RowIconText( 47 | title: "Woman", 48 | onTap: () { 49 | AppNavigator.pop(); 50 | handleSelectGender("Woman"); 51 | }, 52 | ), 53 | ], 54 | ), 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | return true; 30 | } 31 | 32 | void FlutterWindow::OnDestroy() { 33 | if (flutter_controller_) { 34 | flutter_controller_ = nullptr; 35 | } 36 | 37 | Win32Window::OnDestroy(); 38 | } 39 | 40 | LRESULT 41 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 42 | WPARAM const wparam, 43 | LPARAM const lparam) noexcept { 44 | // Give Flutter, including plugins, an opportunity to handle window messages. 45 | if (flutter_controller_) { 46 | std::optional result = 47 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 48 | lparam); 49 | if (result) { 50 | return *result; 51 | } 52 | } 53 | 54 | switch (message) { 55 | case WM_FONTCHANGE: 56 | flutter_controller_->engine()->ReloadSystemFonts(); 57 | break; 58 | } 59 | 60 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 61 | } 62 | -------------------------------------------------------------------------------- /lib/features/home/presentation/widgets/category_card.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/app/colors/app_color.dart'; 6 | import 'package:streamskit_mobile/core/util/common/touchable_opacity.dart'; 7 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 8 | import 'package:streamskit_mobile/features/home/data/model/category_model.dart'; 9 | 10 | class CategoryCard extends StatelessWidget { 11 | final CategoryModel categoryModel; 12 | final Function() onTap; 13 | final bool isCheck; 14 | const CategoryCard({ 15 | super.key, 16 | required this.categoryModel, 17 | required this.onTap, 18 | required this.isCheck, 19 | }); 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return TouchableOpacity( 24 | onTap: onTap, 25 | child: Container( 26 | margin: EdgeInsets.only(right: 10.sp), 27 | padding: EdgeInsets.symmetric( 28 | horizontal: 16.sp, 29 | vertical: 4.sp, 30 | ), 31 | decoration: BoxDecoration( 32 | borderRadius: BorderRadius.circular(30.sp), 33 | color: isCheck ? colorPink : fCD, 34 | ), 35 | child: Row( 36 | mainAxisAlignment: MainAxisAlignment.center, 37 | crossAxisAlignment: CrossAxisAlignment.center, 38 | children: [ 39 | Container( 40 | padding: EdgeInsets.only(bottom: 2.sp), 41 | child: Image.asset( 42 | categoryModel.image, 43 | height: 12.sp, 44 | width: 12.sp, 45 | fit: BoxFit.cover, 46 | ), 47 | ), 48 | SizedBox(width: 3.sp), 49 | Text( 50 | categoryModel.title, 51 | style: TextStyle( 52 | color: mCL, 53 | fontSize: 10.sp, 54 | ), 55 | ) 56 | ], 57 | ), 58 | ), 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/widgets/content_setting.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Package imports: 5 | import 'package:flutter_phosphor_icons/flutter_phosphor_icons.dart'; 6 | 7 | // Project imports: 8 | import 'package:streamskit_mobile/core/app/colors/app_color.dart'; 9 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 10 | import 'package:streamskit_mobile/features/profile/presentation/widgets/row_icon_text.dart'; 11 | 12 | class ContentSetting extends StatelessWidget { 13 | const ContentSetting({ 14 | super.key, 15 | }); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Column( 20 | crossAxisAlignment: CrossAxisAlignment.start, 21 | children: [ 22 | Text( 23 | "CONTENT & ACTIVITY", 24 | style: TextStyle( 25 | fontSize: 10.sp, 26 | color: Colors.grey, 27 | fontWeight: FontWeight.w700, 28 | ), 29 | ), 30 | SizedBox(height: 8.sp), 31 | RowIconText( 32 | title: "Push notifications", 33 | colorLeading: mCL, 34 | sizeLeading: 15.sp, 35 | textStyle: TextStyle(color: mCL, fontSize: 11.sp), 36 | iconLeading: PhosphorIcons.bell, 37 | onTap: () {}, 38 | ), 39 | SizedBox(height: 8.sp), 40 | RowIconText( 41 | title: "Language", 42 | colorLeading: mCL, 43 | sizeLeading: 15.sp, 44 | textStyle: TextStyle(color: mCL, fontSize: 11.sp), 45 | iconLeading: PhosphorIcons.translate_thin, 46 | onTap: () {}, 47 | ), 48 | SizedBox(height: 8.sp), 49 | RowIconText( 50 | title: "Watch history", 51 | colorLeading: mCL, 52 | sizeLeading: 15.sp, 53 | textStyle: TextStyle(color: mCL, fontSize: 11.sp), 54 | iconLeading: PhosphorIcons.clock_counter_clockwise_thin, 55 | onTap: () {}, 56 | ), 57 | ], 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | streamskit_mobile 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /lib/features/stream/presentation/widgets/viewer_widget.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/util/numeral/numeral.dart'; 6 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 7 | 8 | class ViewerWidget extends StatefulWidget { 9 | const ViewerWidget({super.key}); 10 | 11 | @override 12 | State createState() => _ViewerWidgetState(); 13 | } 14 | 15 | class _ViewerWidgetState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | return Container( 19 | padding: EdgeInsets.symmetric(horizontal: 4.sp, vertical: 4), 20 | height: 30.sp, 21 | decoration: BoxDecoration( 22 | borderRadius: BorderRadius.circular(100.sp), 23 | color: Colors.white.withOpacity(0.25), 24 | ), 25 | child: Center( 26 | child: Row( 27 | mainAxisSize: MainAxisSize.min, 28 | children: [ 29 | Icon( 30 | Icons.remove_red_eye_outlined, 31 | color: Colors.white, 32 | size: 14.sp, 33 | ), 34 | SizedBox( 35 | width: 2.sp, 36 | ), 37 | Text( 38 | const Numeral(55411).format(), 39 | style: TextStyle(fontSize: 11.sp, color: Colors.white), 40 | ), 41 | SizedBox( 42 | width: 2.6.sp, 43 | ), 44 | Container( 45 | height: 16.sp, 46 | padding: EdgeInsets.symmetric(horizontal: 4.8.sp), 47 | decoration: BoxDecoration( 48 | color: Colors.red.shade700, 49 | borderRadius: BorderRadius.circular(18.sp), 50 | ), 51 | child: Center( 52 | child: Text( 53 | 'Live', 54 | style: TextStyle(fontSize: 10.sp, color: Colors.white), 55 | ), 56 | ), 57 | ), 58 | ], 59 | ), 60 | ), 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /test/features/home/data/models/live_stream_model_test.dart: -------------------------------------------------------------------------------- 1 | // Dart imports: 2 | import 'dart:convert'; 3 | 4 | // Package imports: 5 | import 'package:flutter_test/flutter_test.dart'; 6 | 7 | // Project imports: 8 | import 'package:streamskit_mobile/features/home/data/model/live_stream_model.dart'; 9 | import '../../../../fixtures/fixture_reader.dart'; 10 | 11 | void main() { 12 | final LiveStreamModel liveStreamModel = listLiveStreamFake[0]; 13 | 14 | test( 15 | 'should be a subclass of LiveStream entity', 16 | () async { 17 | // assert 18 | expect(liveStreamModel, isA()); 19 | }, 20 | ); 21 | 22 | group('fromMap', () { 23 | test( 24 | 'should return a valid model when the JSON', 25 | () async { 26 | // arrange 27 | final List arrayRaw = 28 | jsonDecode(fixture('live_stream_model.json')); 29 | // act 30 | final List result = arrayRaw 31 | .map( 32 | (liveStreamJson) => LiveStreamModel.fromMap(liveStreamJson)) 33 | .toList(); 34 | // assert 35 | expect(result.length, arrayRaw.length); 36 | }, 37 | ); 38 | }); 39 | 40 | group('toMap', () { 41 | test( 42 | 'should return a MAP map containing the proper data', 43 | () async { 44 | // act 45 | final result = liveStreamModel.toMap(); 46 | // assert 47 | final expectedMap = { 48 | 'peopleParticipant': 910, 49 | 'type': 1, 50 | 'urlToImage': urlImageGame, 51 | }; 52 | expect(result, expectedMap); 53 | }, 54 | ); 55 | }); 56 | 57 | group('toJson', () { 58 | test( 59 | 'should return a JSON map containing the proper data', 60 | () async { 61 | // act 62 | final result = liveStreamModel.toJson(); 63 | // assert 64 | final expectedMap = { 65 | 'peopleParticipant': 910, 66 | 'type': 1, 67 | 'urlToImage': urlImageGame, 68 | }; 69 | expect(result, jsonEncode(expectedMap)); 70 | }, 71 | ); 72 | }); 73 | } 74 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | 26 | 30 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /lib/core/util/styles/profile_style.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/app/colors/app_color.dart'; 6 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 7 | 8 | const Color colorDividerBottomSheet = Color(0xFFC4C4C4); 9 | const Color colorDividerBottomSheetDark = Color(0xFF595959); 10 | const Color colorBorderTextField = Color(0xFFC5D0CF); 11 | 12 | /// Text size: 13 color: mCL weight: 700 13 | TextStyle text13w700mCL = TextStyle( 14 | color: mCL, 15 | fontSize: 13.sp, 16 | fontWeight: FontWeight.w700, 17 | overflow: TextOverflow.ellipsis, 18 | ); 19 | 20 | /// Text size: 13 color: mCL 21 | TextStyle text13mCL = TextStyle( 22 | color: mCL, 23 | fontSize: 13.sp, 24 | overflow: TextOverflow.ellipsis, 25 | ); 26 | 27 | /// Text size: 11 color: mCL 28 | TextStyle text11mCL = TextStyle( 29 | color: mCL, 30 | fontSize: 11.sp, 31 | overflow: TextOverflow.ellipsis, 32 | ); 33 | 34 | /// Text size: 11 color: colorBlack1 35 | TextStyle text11cB1 = TextStyle( 36 | color: colorBlack1, 37 | fontSize: 11.sp, 38 | overflow: TextOverflow.ellipsis, 39 | ); 40 | 41 | ///Text size: 11 color : mGB 42 | TextStyle text11mGB = TextStyle( 43 | color: mGB, 44 | fontSize: 11.sp, 45 | overflow: TextOverflow.ellipsis, 46 | ); 47 | 48 | ///Text size: 11 color : mGM 49 | TextStyle text11mGM = TextStyle( 50 | color: mGM, 51 | fontSize: 11.sp, 52 | overflow: TextOverflow.ellipsis, 53 | ); 54 | 55 | ///Text size: 11 color : mGD 56 | TextStyle text11mGD = TextStyle( 57 | color: mGD, 58 | fontSize: 11.sp, 59 | overflow: TextOverflow.ellipsis, 60 | ); 61 | 62 | ///Text size: 9 color: mCL 63 | TextStyle text9mCL = TextStyle( 64 | color: mCL, 65 | fontSize: 9.sp, 66 | overflow: TextOverflow.ellipsis, 67 | height: 1.4, 68 | ); 69 | 70 | ///Text size: 9 color: mGM 71 | TextStyle text9mGM = TextStyle( 72 | color: mGM, 73 | fontSize: 9.sp, 74 | overflow: TextOverflow.ellipsis, 75 | ); 76 | 77 | ///Text size: 7 color: mCL 78 | TextStyle text7mCL = TextStyle( 79 | color: mCL, 80 | fontSize: 7.sp, 81 | overflow: TextOverflow.ellipsis, 82 | height: 1.4, 83 | ); 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # StreamOS - UI Live Streaming App using Flutter 🛠️ 🎮 2 | 3 | Computador 4 | 5 | StreamOS UI is a Flutter application with a sleek and intuitive user interface. The app features a robust login system, which allows users to sign in using their Google or Apple accounts via Firebase. 6 | 7 | The app has been built using Test-Driven Development (TDD) approach, ensuring that the login functionality is thoroughly tested through unit tests. 8 | 9 | ## Screenshots 10 | 11 |

12 | 13 | 14 | 15 | 16 |

17 |

18 | 19 | 20 | 21 | 22 |

23 | 24 | ## Features 25 | 26 | - Intuitive user interface 27 | - Login with Google/Apple using Firebase 28 | 29 | ## Getting Started 30 | 31 | To get started with StreamOS UI, follow the instructions below. 32 | 33 | ### Prerequisites 34 | - Flutter 35 | - Firebase account 36 | 37 | ### Installation 38 | 1. Clone the repository: `git clone https://github.com/lambiengcode/flutter-live-stream-ui.git` 39 | 2. Install dependencies: `flutter pub get` 40 | 3. Run the app: `flutter run` 41 | 42 | ## Conclusion 43 | 44 | StreamOS UI is a sleek and intuitive Flutter application with a robust login system. The app's login functionality has been implemented using Firebase, ensuring a secure and seamless user experience. 45 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleDisplayName 10 | StreamOS 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | com.streams.kit 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | $(FLUTTER_BUILD_NAME) 23 | CFBundleSignature 24 | ???? 25 | CFBundleURLTypes 26 | 27 | 28 | CFBundleTypeRole 29 | Editor 30 | CFBundleURLName 31 | com.streams.kit 32 | CFBundleURLSchemes 33 | 34 | 35 | com.googleusercontent.apps.38681732543-a1c15bbp5qra3vdf4c26f8h4qj4mp8hm 36 | https 37 | 38 | 39 | 40 | CFBundleVersion 41 | $(FLUTTER_BUILD_NUMBER) 42 | LSRequiresIPhoneOS 43 | 44 | UIApplicationSupportsIndirectInputEvents 45 | 46 | UILaunchStoryboardName 47 | LaunchScreen 48 | UIMainStoryboardFile 49 | Main 50 | UISupportedInterfaceOrientations 51 | 52 | UIInterfaceOrientationPortrait 53 | UIInterfaceOrientationLandscapeLeft 54 | UIInterfaceOrientationLandscapeRight 55 | 56 | UISupportedInterfaceOrientations~ipad 57 | 58 | UIInterfaceOrientationPortrait 59 | UIInterfaceOrientationPortraitUpsideDown 60 | UIInterfaceOrientationLandscapeLeft 61 | UIInterfaceOrientationLandscapeRight 62 | 63 | UIViewControllerBasedStatusBarAppearance 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /lib/core/util/sizer_custom/util.dart: -------------------------------------------------------------------------------- 1 | part of 'sizer.dart'; 2 | 3 | class SizerUtil { 4 | /// Device's BoxConstraints 5 | static late BoxConstraints boxConstraints; 6 | 7 | /// Device's Orientation 8 | static late Orientation orientation; 9 | 10 | /// Type of Device 11 | /// 12 | /// This can either be mobile or tablet 13 | static late DeviceType deviceType; 14 | 15 | /// Device's Height 16 | static late double height; 17 | 18 | /// Device's Width 19 | static late double width; 20 | 21 | /// Sets the Screen's size and Device's Orientation, 22 | /// BoxConstraints, Height, and Width 23 | static void setScreenSize( 24 | BoxConstraints constraints, Orientation currentOrientation) { 25 | // Sets boxconstraints and orientation 26 | boxConstraints = constraints; 27 | orientation = currentOrientation; 28 | 29 | // Sets screen width and height 30 | if (orientation == Orientation.portrait) { 31 | width = boxConstraints.maxWidth; 32 | height = boxConstraints.maxHeight; 33 | } else { 34 | width = boxConstraints.maxHeight; 35 | height = boxConstraints.maxWidth; 36 | } 37 | 38 | // Sets ScreenType 39 | if (kIsWeb) { 40 | deviceType = DeviceType.web; 41 | } else if (Platform.isAndroid || Platform.isIOS) { 42 | if ((orientation == Orientation.portrait && width < 600) || 43 | (orientation == Orientation.landscape && height < 600)) { 44 | deviceType = DeviceType.mobile; 45 | } else { 46 | deviceType = DeviceType.tablet; 47 | } 48 | } else if (Platform.isMacOS) { 49 | deviceType = DeviceType.mac; 50 | } else if (Platform.isWindows) { 51 | deviceType = DeviceType.windows; 52 | } else if (Platform.isLinux) { 53 | deviceType = DeviceType.linux; 54 | } else { 55 | deviceType = DeviceType.fuchsia; 56 | } 57 | } 58 | 59 | // for responsive web 60 | static getWebResponsiveSize({smallSize, mediumSize, largeSize}) { 61 | return width < 600 62 | ? smallSize //'phone' 63 | : width >= 600 && width <= 1024 64 | ? mediumSize //'tablet' 65 | : largeSize; //'desktop'; 66 | } 67 | 68 | static bool get isTablet => deviceType == DeviceType.tablet; 69 | } 70 | 71 | /// Type of Device 72 | /// 73 | /// This can be either mobile or tablet 74 | enum DeviceType { mobile, tablet, web, mac, windows, linux, fuchsia } 75 | -------------------------------------------------------------------------------- /lib/features/stream/presentation/screens/stream_screen.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | // ignore_for_file: depend_on_referenced_packages 3 | 4 | // Flutter imports: 5 | import 'package:flutter/material.dart'; 6 | 7 | // Package imports: 8 | import 'package:provider/provider.dart'; 9 | 10 | // Project imports: 11 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 12 | import 'package:streamskit_mobile/features/stream/presentation/widgets/app_bar_stream.dart'; 13 | import 'package:streamskit_mobile/features/stream/presentation/widgets/comment_widget.dart'; 14 | import 'package:streamskit_mobile/features/stream/provider/hearts_provider.dart'; 15 | 16 | class StreamScreen extends StatefulWidget { 17 | const StreamScreen({super.key}); 18 | 19 | @override 20 | State createState() => _StreamScreenState(); 21 | } 22 | 23 | class _StreamScreenState extends State { 24 | @override 25 | Widget build(BuildContext context) { 26 | return MultiProvider( 27 | providers: [ 28 | ChangeNotifierProvider(create: (context) => FloatingHeartsProvider()), 29 | ], 30 | child: Scaffold( 31 | resizeToAvoidBottomInset: false, 32 | body: Container( 33 | width: double.infinity, 34 | height: double.infinity, 35 | color: Colors.purple.withOpacity(0.2), 36 | child: Stack( 37 | children: [ 38 | Image.asset( 39 | 'assets/images/stream_image.jpg', 40 | fit: BoxFit.fitHeight, 41 | height: double.infinity, 42 | ), 43 | Padding( 44 | padding: 45 | EdgeInsets.symmetric(vertical: 16.sp, horizontal: 16.sp), 46 | child: const AppBarStream(), 47 | ), 48 | Padding( 49 | padding: EdgeInsets.symmetric(horizontal: 20.sp) 50 | .add(EdgeInsets.only(bottom: 10.sp)), 51 | child: const Align( 52 | alignment: Alignment.bottomCenter, 53 | child: Column( 54 | mainAxisSize: MainAxisSize.min, 55 | children: [ 56 | CommentWidgets(), 57 | ], 58 | ), 59 | ), 60 | ), 61 | ], 62 | ), 63 | ), 64 | ), 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 33 30 | ndkVersion flutter.ndkVersion 31 | 32 | compileOptions { 33 | sourceCompatibility JavaVersion.VERSION_1_8 34 | targetCompatibility JavaVersion.VERSION_1_8 35 | } 36 | 37 | kotlinOptions { 38 | jvmTarget = '1.8' 39 | } 40 | 41 | sourceSets { 42 | main.java.srcDirs += 'src/main/kotlin' 43 | } 44 | 45 | defaultConfig { 46 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 47 | applicationId "com.streams.kit" 48 | // You can update the following values to match your application needs. 49 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. 50 | minSdkVersion 24 51 | targetSdkVersion 30 52 | versionCode flutterVersionCode.toInteger() 53 | versionName flutterVersionName 54 | } 55 | 56 | buildTypes { 57 | release { 58 | // TODO: Add your own signing config for the release build. 59 | // Signing with the debug keys for now, so `flutter run --release` works. 60 | signingConfig signingConfigs.debug 61 | } 62 | } 63 | } 64 | 65 | flutter { 66 | source '../..' 67 | } 68 | 69 | dependencies { 70 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 71 | } 72 | -------------------------------------------------------------------------------- /lib/features/auth/domain/entities/social.dart: -------------------------------------------------------------------------------- 1 | // Dart imports: 2 | import 'dart:convert'; 3 | 4 | class SocialValue { 5 | final String fullName; 6 | final String? facebookId; 7 | final String? googleId; 8 | final String? appleId; 9 | SocialValue({ 10 | required this.fullName, 11 | this.facebookId, 12 | this.googleId, 13 | this.appleId, 14 | }); 15 | 16 | SocialValue copyWith({ 17 | String? fullName, 18 | String? email, 19 | String? facebookId, 20 | String? googleId, 21 | String? appleId, 22 | }) { 23 | return SocialValue( 24 | fullName: fullName ?? this.fullName, 25 | facebookId: facebookId ?? this.facebookId, 26 | googleId: googleId ?? this.googleId, 27 | appleId: appleId ?? this.appleId, 28 | ); 29 | } 30 | 31 | Map toMap() { 32 | Map result = { 33 | 'fullName': fullName, 34 | }; 35 | 36 | if (googleId != null) { 37 | result['credentialId'] = googleId!; 38 | result['socialType'] = 0; 39 | } 40 | 41 | if (appleId != null) { 42 | result['credentialId'] = appleId!; 43 | result['socialType'] = 2; 44 | } 45 | 46 | if (facebookId != null) { 47 | result['credentialId'] = facebookId!; 48 | result['socialType'] = 1; 49 | } 50 | 51 | return result; 52 | } 53 | 54 | factory SocialValue.fromMap(Map map) { 55 | return SocialValue( 56 | fullName: map['fullName'] ?? '', 57 | facebookId: map['facebookId'], 58 | googleId: map['googleId'], 59 | appleId: map['appleId'], 60 | ); 61 | } 62 | 63 | String toJson() => json.encode(toMap()); 64 | 65 | factory SocialValue.fromJson(String source) => 66 | SocialValue.fromMap(json.decode(source)); 67 | 68 | @override 69 | String toString() { 70 | return 'SocialModel(fullName: $fullName, facebookId: $facebookId, googleId: $googleId, appleId: $appleId)'; 71 | } 72 | 73 | @override 74 | bool operator ==(Object other) { 75 | if (identical(this, other)) return true; 76 | 77 | return other is SocialValue && 78 | other.fullName == fullName && 79 | other.facebookId == facebookId && 80 | other.googleId == googleId && 81 | other.appleId == appleId; 82 | } 83 | 84 | @override 85 | int get hashCode { 86 | return fullName.hashCode ^ 87 | facebookId.hashCode ^ 88 | googleId.hashCode ^ 89 | appleId.hashCode; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/features/home/domain/usecases/get_list_live_stream_test.mocks.dart: -------------------------------------------------------------------------------- 1 | // Mocks generated by Mockito 5.3.0 from annotations 2 | // in streamskit_mobile/test/features/home/domain/usecases/get_list_live_stream_test.dart. 3 | // Do not manually edit this file. 4 | 5 | // ignore_for_file: no_leading_underscores_for_library_prefixes 6 | 7 | // Package imports: 8 | import 'package:dartz/dartz.dart' as _i2; 9 | import 'package:mockito/mockito.dart' as _i1; 10 | 11 | // Project imports: 12 | import 'package:streamskit_mobile/core/error/failure.dart' as _i4; 13 | 14 | import 'package:streamskit_mobile/features/home/data/model/live_stream_model.dart' 15 | as _i5; 16 | import 'package:streamskit_mobile/features/home/domain/repositories/live_stream_repository.dart' 17 | as _i3; 18 | 19 | // ignore_for_file: type=lint 20 | // ignore_for_file: avoid_redundant_argument_values 21 | // ignore_for_file: avoid_setters_without_getters 22 | // ignore_for_file: comment_references 23 | // ignore_for_file: implementation_imports 24 | // ignore_for_file: invalid_use_of_visible_for_testing_member 25 | // ignore_for_file: prefer_const_constructors 26 | // ignore_for_file: unnecessary_parenthesis 27 | // ignore_for_file: camel_case_types 28 | // ignore_for_file: subtype_of_sealed_class 29 | 30 | class _FakeEither_0 extends _i1.SmartFake implements _i2.Either { 31 | _FakeEither_0( 32 | Object parent, 33 | Invocation parentInvocation, 34 | ) : super( 35 | parent, 36 | parentInvocation, 37 | ); 38 | } 39 | 40 | /// A class which mocks [LiveStreamRepository]. 41 | /// 42 | /// See the documentation for Mockito's code generation for more information. 43 | class MockLiveStreamRepository extends _i1.Mock 44 | implements _i3.LiveStreamRepository { 45 | @override 46 | _i2.Either<_i4.Failure, List<_i5.LiveStreamModel>> getLiveStreams() => 47 | (super.noSuchMethod( 48 | Invocation.method( 49 | #getLiveStreams, 50 | [], 51 | ), 52 | returnValue: _FakeEither_0<_i4.Failure, List<_i5.LiveStreamModel>>( 53 | this, 54 | Invocation.method( 55 | #getLiveStreams, 56 | [], 57 | ), 58 | ), 59 | returnValueForMissingStub: 60 | _FakeEither_0<_i4.Failure, List<_i5.LiveStreamModel>>( 61 | this, 62 | Invocation.method( 63 | #getLiveStreams, 64 | [], 65 | ), 66 | ), 67 | ) as _i2.Either<_i4.Failure, List<_i5.LiveStreamModel>>); 68 | } 69 | -------------------------------------------------------------------------------- /lib/core/util/path_helper.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: depend_on_referenced_packages 2 | 3 | // Dart imports: 4 | import 'dart:io'; 5 | 6 | // Flutter imports: 7 | import 'package:flutter/services.dart'; 8 | 9 | // Package imports: 10 | import 'package:path_provider/path_provider.dart'; 11 | 12 | // Project imports: 13 | import 'package:streamskit_mobile/core/util/logger.dart'; 14 | 15 | class PathHelper { 16 | static Future deleteCacheImageDir(String path) async { 17 | final cacheDir = Directory(path); 18 | if (cacheDir.existsSync()) { 19 | cacheDir.deleteSync(recursive: true); 20 | } 21 | } 22 | 23 | static Future createDirStreamOS() async { 24 | String tempAskanyDir = await tempDirStreamOS; 25 | String localStoreAskanyDir = await localStoreDirStreamOS; 26 | Directory myDir = Directory(tempAskanyDir); 27 | Directory localDir = Directory(localStoreAskanyDir); 28 | if (!myDir.existsSync()) { 29 | await myDir.create(); 30 | } 31 | 32 | if (!localDir.existsSync()) { 33 | await localDir.create(); 34 | } 35 | } 36 | 37 | static Future get tempDirStreamOS async => 38 | '${(await getTemporaryDirectory()).path}/streamOS'; 39 | 40 | static Future get localStoreDirStreamOS async => 41 | '${(await getTemporaryDirectory()).path}/hive'; 42 | 43 | static Future get appDir async => 44 | await getApplicationDocumentsDirectory(); 45 | 46 | static Future get downloadsDir async { 47 | Directory downloadsDirectory; 48 | try { 49 | if (Platform.isIOS) { 50 | downloadsDirectory = await getLibraryDirectory(); 51 | } else { 52 | downloadsDirectory = await getApplicationSupportDirectory(); 53 | } 54 | 55 | return downloadsDirectory; 56 | } on PlatformException { 57 | UtilLogger.log('Could not get the downloads directory'); 58 | return null; 59 | } 60 | } 61 | 62 | static Future getTempSize() async { 63 | String tempAskanyDir = await tempDirStreamOS; 64 | Directory myDir = Directory(tempAskanyDir); 65 | 66 | if (!myDir.existsSync()) return 0; 67 | 68 | return myDir.listSync().isEmpty ? 0 : ((myDir.statSync().size - 64) * 1024); 69 | } 70 | 71 | static Future clearTempDir() async { 72 | String tempAskanyDir = await tempDirStreamOS; 73 | Directory myDir = Directory(tempAskanyDir); 74 | 75 | if (!myDir.existsSync()) return; 76 | 77 | myDir.deleteSync(recursive: true); 78 | myDir.create(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/features/home/presentation/widgets/list_category_home.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/app/colors/app_color.dart'; 6 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 7 | import 'package:streamskit_mobile/features/home/data/model/category_model.dart'; 8 | import 'package:streamskit_mobile/features/home/presentation/widgets/category_card.dart'; 9 | 10 | class ListCategoryHome extends StatefulWidget { 11 | const ListCategoryHome({super.key}); 12 | 13 | @override 14 | State createState() => _ListCategoryHomeState(); 15 | } 16 | 17 | class _ListCategoryHomeState extends State { 18 | int _currentIndex = 0; 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return Column( 23 | crossAxisAlignment: CrossAxisAlignment.start, 24 | children: [ 25 | Padding( 26 | padding: EdgeInsets.symmetric(horizontal: 16.sp), 27 | child: Row( 28 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 29 | children: [ 30 | Text( 31 | 'Categories', 32 | style: TextStyle( 33 | color: Colors.white, 34 | fontSize: 13.sp, 35 | fontWeight: FontWeight.w700, 36 | ), 37 | ), 38 | Text( 39 | 'View all', 40 | style: TextStyle( 41 | color: colorPink, 42 | fontSize: 11.sp, 43 | ), 44 | ), 45 | ], 46 | ), 47 | ), 48 | SizedBox(height: 8.sp), 49 | SizedBox( 50 | height: 32.5.sp, 51 | width: double.infinity, 52 | child: ListView.builder( 53 | padding: EdgeInsets.symmetric(horizontal: 16.sp), 54 | itemCount: listCategoryFake.length, 55 | shrinkWrap: true, 56 | scrollDirection: Axis.horizontal, 57 | itemBuilder: ((context, index) { 58 | return CategoryCard( 59 | categoryModel: listCategoryFake[index], 60 | isCheck: _currentIndex == index, 61 | onTap: () { 62 | setState(() { 63 | _currentIndex = index; 64 | }); 65 | }, 66 | ); 67 | }), 68 | ), 69 | ), 70 | ], 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lib/features/app/app.dart: -------------------------------------------------------------------------------- 1 | // Dart imports: 2 | import 'dart:async'; 3 | 4 | // Flutter imports: 5 | import 'package:flutter/material.dart'; 6 | 7 | // Package imports: 8 | import 'package:flutter_bloc/flutter_bloc.dart'; 9 | 10 | // Project imports: 11 | import 'package:streamskit_mobile/core/app/constant/constants.dart'; 12 | import 'package:streamskit_mobile/core/app/themes/themes.dart'; 13 | import 'package:streamskit_mobile/core/navigator/app_pages.dart'; 14 | import 'package:streamskit_mobile/core/util/after_layout_mixin.dart'; 15 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 16 | import 'package:streamskit_mobile/features/auth/presentation/bloc/auth_bloc.dart'; 17 | import 'package:streamskit_mobile/features/auth/presentation/screens/sign_in_screen.dart'; 18 | import 'package:streamskit_mobile/features/home.dart'; 19 | import 'package:streamskit_mobile/features/home/presentation/splash_screen.dart'; 20 | 21 | class App extends StatefulWidget { 22 | const App({super.key}); 23 | 24 | @override 25 | State createState() { 26 | return _AppState(); 27 | } 28 | } 29 | 30 | class _AppState extends State with AfterLayoutMixin { 31 | bool _isInitial = true; 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return Sizer( 36 | builder: ((context, orientation, deviceType) { 37 | return MaterialApp( 38 | navigatorKey: AppNavigator.navigatorKey, 39 | debugShowCheckedModeBanner: false, 40 | theme: AppTheme.light().data, 41 | darkTheme: AppTheme.dark().data, 42 | themeMode: ThemeMode.dark, 43 | navigatorObservers: [NavigatorObserver()], 44 | onGenerateRoute: (settings) { 45 | return AppNavigator().getRoute(settings); 46 | }, 47 | home: BlocBuilder( 48 | builder: (context, auth) { 49 | if (_isInitial) { 50 | return const SplashScreen(); 51 | } 52 | 53 | bool isLogined = auth is AuthSuccess; 54 | if (isLogined) { 55 | return const Home(); 56 | } 57 | 58 | return const SignInScreen(); 59 | }, 60 | ), 61 | ); 62 | }), 63 | ); 64 | } 65 | 66 | @override 67 | FutureOr afterFirstLayout(BuildContext context) { 68 | Future.delayed(const Duration(milliseconds: delayASecond), () { 69 | setState(() { 70 | _isInitial = false; 71 | }); 72 | }); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/widgets/row_icon_text.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/util/common/touchable_opacity.dart'; 6 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 7 | import 'package:streamskit_mobile/core/util/styles/profile_style.dart'; 8 | 9 | class RowIconText extends StatelessWidget { 10 | final String title; 11 | final IconData? iconLeading; 12 | final Color? colorLeading; 13 | final double? sizeLeading; 14 | final IconData? iconSuffix; 15 | final Color? colorSuffix; 16 | final double? sizeSuffix; 17 | final TextStyle? textStyle; 18 | final Function()? onTap; 19 | const RowIconText({ 20 | super.key, 21 | required this.title, 22 | this.iconLeading, 23 | this.onTap, 24 | this.colorLeading, 25 | this.iconSuffix, 26 | this.colorSuffix, 27 | this.sizeLeading, 28 | this.sizeSuffix, 29 | this.textStyle, 30 | }); 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | return TouchableOpacity( 35 | onTap: onTap ?? () {}, 36 | child: Padding( 37 | padding: EdgeInsets.symmetric(vertical: 8.sp), 38 | child: iconLeading == null 39 | ? Align( 40 | alignment: Alignment.center, 41 | child: Text( 42 | title, 43 | style: textStyle ?? text13mCL, 44 | ), 45 | ) 46 | : Row( 47 | children: [ 48 | Icon( 49 | iconLeading, 50 | size: sizeLeading ?? 18.sp, 51 | color: colorLeading, 52 | ), 53 | SizedBox( 54 | width: 10.sp, 55 | ), 56 | Text( 57 | title, 58 | style: textStyle ?? text13mCL, 59 | ), 60 | const Spacer(), 61 | iconSuffix != null 62 | ? Padding( 63 | padding: EdgeInsets.only(right: 8.0.sp), 64 | child: Icon( 65 | iconSuffix, 66 | size: sizeSuffix ?? 9.sp, 67 | color: colorSuffix, 68 | ), 69 | ) 70 | : const SizedBox() 71 | ], 72 | ), 73 | ), 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/features/stream/presentation/widgets/hearts_animation.dart: -------------------------------------------------------------------------------- 1 | // Dart imports: 2 | // ignore_for_file: depend_on_referenced_packages 3 | 4 | // Dart imports: 5 | import 'dart:math' as math; 6 | import 'dart:ui'; 7 | 8 | // Flutter imports: 9 | import 'package:flutter/material.dart'; 10 | 11 | // Package imports: 12 | import 'package:provider/provider.dart'; 13 | 14 | // Project imports: 15 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 16 | import 'package:streamskit_mobile/features/stream/provider/hearts_provider.dart'; 17 | 18 | class HeartAnimation extends StatefulWidget { 19 | const HeartAnimation({super.key}); 20 | 21 | @override 22 | HeartStateAnimation createState() => HeartStateAnimation(); 23 | } 24 | 25 | class HeartStateAnimation extends State 26 | with SingleTickerProviderStateMixin { 27 | late AnimationController controller; 28 | 29 | final Color _color = Color((math.Random().nextDouble() * 0xFFFFFF).toInt()); 30 | final double right = math.Random().nextInt(20).toDouble(); 31 | final int randomSize = math.Random().nextInt(18); 32 | double opacity = 0.7; 33 | 34 | @override 35 | void dispose() { 36 | controller.dispose(); 37 | super.dispose(); 38 | } 39 | 40 | @override 41 | void initState() { 42 | controller = AnimationController( 43 | vsync: this, 44 | duration: const Duration(seconds: 3), 45 | ); 46 | _startAnimation(controller); 47 | super.initState(); 48 | } 49 | 50 | void _startAnimation(AnimationController controller) { 51 | controller.forward().whenComplete(() { 52 | FloatingHeartsProvider floatingHeartsProvider = 53 | context.read(); 54 | floatingHeartsProvider.removeHeart(widget.key); 55 | // controller.dispose(); 56 | }); 57 | } 58 | 59 | @override 60 | Widget build(BuildContext context) { 61 | Size size = Size(30.sp, 150.sp); 62 | 63 | return AnimatedBuilder( 64 | animation: controller, 65 | builder: (context, snapshot) { 66 | final value = controller.value; 67 | double? bottom = lerpDouble(10.sp, 30.sp + size.height * 0.25, value); 68 | opacity = lerpDouble(0.7, 0, value)!; 69 | 70 | return Positioned( 71 | bottom: bottom, 72 | right: right, 73 | child: Icon(Icons.favorite, 74 | color: _color.withOpacity(opacity), 75 | size: 20.sp //(size.width * 0.05 + randomSize).toDouble(), 76 | ), 77 | ); 78 | }, 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/features/stream/presentation/widgets/name_live_widget.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/util/common/touchable_opacity.dart'; 6 | import 'package:streamskit_mobile/core/util/custom_image/custom_netword_image.dart'; 7 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 8 | 9 | class FullnameLiveWidget extends StatelessWidget { 10 | const FullnameLiveWidget({super.key}); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Row( 15 | mainAxisAlignment: MainAxisAlignment.start, 16 | children: [ 17 | CustomNetworkImage( 18 | height: 32.sp, 19 | width: 32.sp, 20 | urlToImage: 21 | 'https://my-test-11.slatic.net/p/96b9cce35f664d67479547587686742a.jpg', 22 | shape: BoxShape.circle, 23 | ), 24 | SizedBox( 25 | width: 4.sp, 26 | ), 27 | Expanded( 28 | child: SizedBox( 29 | height: 48.sp, 30 | child: Column( 31 | mainAxisAlignment: MainAxisAlignment.center, 32 | crossAxisAlignment: CrossAxisAlignment.start, 33 | children: [ 34 | Text( 35 | 'Lord Busuz', 36 | overflow: TextOverflow.ellipsis, 37 | style: TextStyle( 38 | fontSize: 13.sp, 39 | fontWeight: FontWeight.w700, 40 | color: Colors.white), 41 | ), 42 | Text( 43 | '159K Followers', 44 | overflow: TextOverflow.ellipsis, 45 | style: TextStyle( 46 | fontSize: 10.sp, 47 | fontWeight: FontWeight.w400, 48 | color: Colors.white), 49 | ), 50 | ], 51 | ), 52 | ), 53 | ), 54 | TouchableOpacity( 55 | child: Container( 56 | margin: EdgeInsets.only(right: 8.sp), 57 | padding: EdgeInsets.symmetric(horizontal: 8.sp, vertical: 4.8.sp), 58 | decoration: BoxDecoration( 59 | color: Colors.blue.shade700, 60 | borderRadius: BorderRadius.circular(20.sp), 61 | ), 62 | child: Text( 63 | 'Follow', 64 | style: TextStyle(fontSize: 10.sp, color: Colors.white), 65 | ), 66 | ), 67 | ), 68 | ], 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/widgets/bottom_sheet_choose_option.dart: -------------------------------------------------------------------------------- 1 | // Flutter imports: 2 | import 'package:flutter/material.dart'; 3 | 4 | // Project imports: 5 | import 'package:streamskit_mobile/core/app/colors/app_color.dart'; 6 | import 'package:streamskit_mobile/core/navigator/app_pages.dart'; 7 | import 'package:streamskit_mobile/core/navigator/app_routes.dart'; 8 | import 'package:streamskit_mobile/core/util/sizer_custom/sizer.dart'; 9 | import 'package:streamskit_mobile/core/util/styles/profile_style.dart'; 10 | import 'package:streamskit_mobile/features/profile/presentation/widgets/row_icon_text.dart'; 11 | 12 | class BottomSheetChooseOption extends StatelessWidget { 13 | const BottomSheetChooseOption({super.key}); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Container( 18 | padding: EdgeInsets.symmetric(horizontal: 16.sp).add( 19 | EdgeInsets.only(bottom: 10.sp), 20 | ), 21 | decoration: BoxDecoration( 22 | borderRadius: BorderRadius.vertical( 23 | top: Radius.circular(20.sp), 24 | ), 25 | color: Colors.grey.shade900, 26 | ), 27 | child: Column( 28 | mainAxisSize: MainAxisSize.min, 29 | crossAxisAlignment: CrossAxisAlignment.start, 30 | children: [ 31 | const DividerBottomSheet(), 32 | SizedBox( 33 | height: 8.sp, 34 | ), 35 | const RowIconText( 36 | title: "Creator tools", 37 | iconLeading: Icons.manage_accounts_outlined, 38 | iconSuffix: Icons.circle, 39 | colorSuffix: Colors.red, 40 | ), 41 | Divider( 42 | thickness: 0.2, 43 | color: mCU, 44 | ), 45 | RowIconText( 46 | title: "Settings and privacy", 47 | iconLeading: Icons.settings_outlined, 48 | onTap: () { 49 | AppNavigator.pop(); 50 | AppNavigator.push( 51 | Routes.settingRoute, 52 | ); 53 | }, 54 | ), 55 | ], 56 | ), 57 | ); 58 | } 59 | } 60 | 61 | class DividerBottomSheet extends StatelessWidget { 62 | const DividerBottomSheet({super.key}); 63 | 64 | @override 65 | Widget build(BuildContext context) { 66 | return Align( 67 | alignment: Alignment.center, 68 | child: Container( 69 | height: 3.sp, 70 | width: 60.sp, 71 | decoration: BoxDecoration( 72 | color: colorDividerBottomSheetDark, 73 | borderRadius: BorderRadius.circular(30), 74 | ), 75 | ), 76 | ); 77 | } 78 | } 79 | --------------------------------------------------------------------------------