diff --git a/assets.rar b/assets.rar deleted file mode 100644 index 297775c..0000000 Binary files a/assets.rar and /dev/null differ diff --git a/assets/facebook.png b/assets/facebook.png new file mode 100644 index 0000000..8f49364 Binary files /dev/null and b/assets/facebook.png differ diff --git a/assets/fonts/Billabong.ttf b/assets/fonts/Billabong.ttf new file mode 100644 index 0000000..0df4bf6 Binary files /dev/null and b/assets/fonts/Billabong.ttf differ diff --git a/assets/images/account_active_icon.svg b/assets/images/account_active_icon.svg new file mode 100644 index 0000000..69ae99a --- /dev/null +++ b/assets/images/account_active_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/account_icon.svg b/assets/images/account_icon.svg new file mode 100644 index 0000000..2b017b9 --- /dev/null +++ b/assets/images/account_icon.svg @@ -0,0 +1 @@ +image (5) \ No newline at end of file diff --git a/assets/images/camera_icon.svg b/assets/images/camera_icon.svg new file mode 100644 index 0000000..0279244 --- /dev/null +++ b/assets/images/camera_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/comment_icon.svg b/assets/images/comment_icon.svg new file mode 100644 index 0000000..c50fdf9 --- /dev/null +++ b/assets/images/comment_icon.svg @@ -0,0 +1 @@ +icon instagram \ No newline at end of file diff --git a/assets/images/home_active_icon.svg b/assets/images/home_active_icon.svg new file mode 100644 index 0000000..a1e5803 --- /dev/null +++ b/assets/images/home_active_icon.svg @@ -0,0 +1 @@ +homeCreated with Sketch. \ No newline at end of file diff --git a/assets/images/home_icon.svg b/assets/images/home_icon.svg new file mode 100644 index 0000000..f6b1ffa --- /dev/null +++ b/assets/images/home_icon.svg @@ -0,0 +1 @@ +icon instagram \ No newline at end of file diff --git a/assets/images/love_active_icon.svg b/assets/images/love_active_icon.svg new file mode 100644 index 0000000..04fefb6 --- /dev/null +++ b/assets/images/love_active_icon.svg @@ -0,0 +1 @@ +like \ No newline at end of file diff --git a/assets/images/love_icon.svg b/assets/images/love_icon.svg new file mode 100644 index 0000000..3b65caf --- /dev/null +++ b/assets/images/love_icon.svg @@ -0,0 +1 @@ +like \ No newline at end of file diff --git a/assets/images/loved_icon.svg b/assets/images/loved_icon.svg new file mode 100644 index 0000000..c70376e --- /dev/null +++ b/assets/images/loved_icon.svg @@ -0,0 +1 @@ +like \ No newline at end of file diff --git a/assets/images/message_icon.svg b/assets/images/message_icon.svg new file mode 100644 index 0000000..2f96bc5 --- /dev/null +++ b/assets/images/message_icon.svg @@ -0,0 +1 @@ +Untitled-1 \ No newline at end of file diff --git a/assets/images/save_icon.svg b/assets/images/save_icon.svg new file mode 100644 index 0000000..a141198 --- /dev/null +++ b/assets/images/save_icon.svg @@ -0,0 +1 @@ +icon instagram \ No newline at end of file diff --git a/assets/images/search_active_icon.svg b/assets/images/search_active_icon.svg new file mode 100644 index 0000000..1d5b6b3 --- /dev/null +++ b/assets/images/search_active_icon.svg @@ -0,0 +1,2 @@ + + diff --git a/assets/images/search_icon.svg b/assets/images/search_icon.svg new file mode 100644 index 0000000..6a1fd2f --- /dev/null +++ b/assets/images/search_icon.svg @@ -0,0 +1 @@ +icon instagram \ No newline at end of file diff --git a/assets/images/upload_active_icon.svg b/assets/images/upload_active_icon.svg new file mode 100644 index 0000000..954ba39 --- /dev/null +++ b/assets/images/upload_active_icon.svg @@ -0,0 +1 @@ +upload_icon \ No newline at end of file diff --git a/assets/images/upload_icon.svg b/assets/images/upload_icon.svg new file mode 100644 index 0000000..ec71556 --- /dev/null +++ b/assets/images/upload_icon.svg @@ -0,0 +1 @@ +icon instagram \ No newline at end of file diff --git a/assets/instagram_logo.png b/assets/instagram_logo.png new file mode 100644 index 0000000..6b66c82 Binary files /dev/null and b/assets/instagram_logo.png differ diff --git a/clone-instagram-login-Refactoring.zip b/clone-instagram-login-Refactoring.zip deleted file mode 100644 index 8bfb817..0000000 Binary files a/clone-instagram-login-Refactoring.zip and /dev/null differ diff --git a/clone-instagram-login-Refactoring/.gitignore b/clone-instagram-login-Refactoring/.gitignore new file mode 100644 index 0000000..4c574d1 --- /dev/null +++ b/clone-instagram-login-Refactoring/.gitignore @@ -0,0 +1,46 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release + +coverage/ diff --git a/clone-instagram-login-Refactoring/.metadata b/clone-instagram-login-Refactoring/.metadata new file mode 100644 index 0000000..262ceed --- /dev/null +++ b/clone-instagram-login-Refactoring/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: 135454af32477f815a7525073027a3ff9eff1bfd + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 135454af32477f815a7525073027a3ff9eff1bfd + base_revision: 135454af32477f815a7525073027a3ff9eff1bfd + - platform: android + create_revision: 135454af32477f815a7525073027a3ff9eff1bfd + base_revision: 135454af32477f815a7525073027a3ff9eff1bfd + - platform: ios + create_revision: 135454af32477f815a7525073027a3ff9eff1bfd + base_revision: 135454af32477f815a7525073027a3ff9eff1bfd + - platform: linux + create_revision: 135454af32477f815a7525073027a3ff9eff1bfd + base_revision: 135454af32477f815a7525073027a3ff9eff1bfd + - platform: macos + create_revision: 135454af32477f815a7525073027a3ff9eff1bfd + base_revision: 135454af32477f815a7525073027a3ff9eff1bfd + - platform: web + create_revision: 135454af32477f815a7525073027a3ff9eff1bfd + base_revision: 135454af32477f815a7525073027a3ff9eff1bfd + - platform: windows + create_revision: 135454af32477f815a7525073027a3ff9eff1bfd + base_revision: 135454af32477f815a7525073027a3ff9eff1bfd + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/clone-instagram-login-Refactoring/README.md b/clone-instagram-login-Refactoring/README.md new file mode 100644 index 0000000..3a713d8 --- /dev/null +++ b/clone-instagram-login-Refactoring/README.md @@ -0,0 +1,16 @@ +# example_widget_testing + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/clone-instagram-login-Refactoring/analysis_options.yaml b/clone-instagram-login-Refactoring/analysis_options.yaml new file mode 100644 index 0000000..61b6c4d --- /dev/null +++ b/clone-instagram-login-Refactoring/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/clone-instagram-login-Refactoring/android/.gitignore b/clone-instagram-login-Refactoring/android/.gitignore new file mode 100644 index 0000000..6f56801 --- /dev/null +++ b/clone-instagram-login-Refactoring/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/clone-instagram-login-Refactoring/android/app/build.gradle b/clone-instagram-login-Refactoring/android/app/build.gradle new file mode 100644 index 0000000..afb45ef --- /dev/null +++ b/clone-instagram-login-Refactoring/android/app/build.gradle @@ -0,0 +1,71 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.example_widget_testing" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/clone-instagram-login-Refactoring/android/app/src/debug/AndroidManifest.xml b/clone-instagram-login-Refactoring/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..d606aaa --- /dev/null +++ b/clone-instagram-login-Refactoring/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/clone-instagram-login-Refactoring/android/app/src/main/AndroidManifest.xml b/clone-instagram-login-Refactoring/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..27601fa --- /dev/null +++ b/clone-instagram-login-Refactoring/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/clone-instagram-login-Refactoring/android/app/src/main/kotlin/com/example/example_widget_testing/MainActivity.kt b/clone-instagram-login-Refactoring/android/app/src/main/kotlin/com/example/example_widget_testing/MainActivity.kt new file mode 100644 index 0000000..4d5c3cc --- /dev/null +++ b/clone-instagram-login-Refactoring/android/app/src/main/kotlin/com/example/example_widget_testing/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.example_widget_testing + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/clone-instagram-login-Refactoring/android/app/src/main/res/drawable-v21/launch_background.xml b/clone-instagram-login-Refactoring/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/clone-instagram-login-Refactoring/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/clone-instagram-login-Refactoring/android/app/src/main/res/drawable/launch_background.xml b/clone-instagram-login-Refactoring/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/clone-instagram-login-Refactoring/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/clone-instagram-login-Refactoring/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/clone-instagram-login-Refactoring/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/clone-instagram-login-Refactoring/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/clone-instagram-login-Refactoring/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/clone-instagram-login-Refactoring/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/clone-instagram-login-Refactoring/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/clone-instagram-login-Refactoring/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/clone-instagram-login-Refactoring/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/clone-instagram-login-Refactoring/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/clone-instagram-login-Refactoring/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/clone-instagram-login-Refactoring/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/clone-instagram-login-Refactoring/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/clone-instagram-login-Refactoring/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/clone-instagram-login-Refactoring/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/clone-instagram-login-Refactoring/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/clone-instagram-login-Refactoring/android/app/src/main/res/values-night/styles.xml b/clone-instagram-login-Refactoring/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/clone-instagram-login-Refactoring/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/clone-instagram-login-Refactoring/android/app/src/main/res/values/styles.xml b/clone-instagram-login-Refactoring/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..cb1ef88 --- /dev/null +++ b/clone-instagram-login-Refactoring/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/clone-instagram-login-Refactoring/android/app/src/profile/AndroidManifest.xml b/clone-instagram-login-Refactoring/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..d606aaa --- /dev/null +++ b/clone-instagram-login-Refactoring/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/clone-instagram-login-Refactoring/android/build.gradle b/clone-instagram-login-Refactoring/android/build.gradle new file mode 100644 index 0000000..83ae220 --- /dev/null +++ b/clone-instagram-login-Refactoring/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.6.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.1.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/clone-instagram-login-Refactoring/android/gradle.properties b/clone-instagram-login-Refactoring/android/gradle.properties new file mode 100644 index 0000000..94adc3a --- /dev/null +++ b/clone-instagram-login-Refactoring/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/clone-instagram-login-Refactoring/android/gradle/wrapper/gradle-wrapper.properties b/clone-instagram-login-Refactoring/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..cb24abd --- /dev/null +++ b/clone-instagram-login-Refactoring/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip diff --git a/clone-instagram-login-Refactoring/android/settings.gradle b/clone-instagram-login-Refactoring/android/settings.gradle new file mode 100644 index 0000000..44e62bc --- /dev/null +++ b/clone-instagram-login-Refactoring/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/clone-instagram-login-Refactoring/assets/facebook.png b/clone-instagram-login-Refactoring/assets/facebook.png new file mode 100644 index 0000000..8f49364 Binary files /dev/null and b/clone-instagram-login-Refactoring/assets/facebook.png differ diff --git a/clone-instagram-login-Refactoring/assets/fonts/Billabong.ttf b/clone-instagram-login-Refactoring/assets/fonts/Billabong.ttf new file mode 100644 index 0000000..0df4bf6 Binary files /dev/null and b/clone-instagram-login-Refactoring/assets/fonts/Billabong.ttf differ diff --git a/clone-instagram-login-Refactoring/assets/images/account_active_icon.svg b/clone-instagram-login-Refactoring/assets/images/account_active_icon.svg new file mode 100644 index 0000000..69ae99a --- /dev/null +++ b/clone-instagram-login-Refactoring/assets/images/account_active_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/clone-instagram-login-Refactoring/assets/images/account_icon.svg b/clone-instagram-login-Refactoring/assets/images/account_icon.svg new file mode 100644 index 0000000..2b017b9 --- /dev/null +++ b/clone-instagram-login-Refactoring/assets/images/account_icon.svg @@ -0,0 +1 @@ +image (5) \ No newline at end of file diff --git a/clone-instagram-login-Refactoring/assets/images/camera_icon.svg b/clone-instagram-login-Refactoring/assets/images/camera_icon.svg new file mode 100644 index 0000000..0279244 --- /dev/null +++ b/clone-instagram-login-Refactoring/assets/images/camera_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/clone-instagram-login-Refactoring/assets/images/comment_icon.svg b/clone-instagram-login-Refactoring/assets/images/comment_icon.svg new file mode 100644 index 0000000..c50fdf9 --- /dev/null +++ b/clone-instagram-login-Refactoring/assets/images/comment_icon.svg @@ -0,0 +1 @@ +icon instagram \ No newline at end of file diff --git a/clone-instagram-login-Refactoring/assets/images/home_active_icon.svg b/clone-instagram-login-Refactoring/assets/images/home_active_icon.svg new file mode 100644 index 0000000..a1e5803 --- /dev/null +++ b/clone-instagram-login-Refactoring/assets/images/home_active_icon.svg @@ -0,0 +1 @@ +homeCreated with Sketch. \ No newline at end of file diff --git a/clone-instagram-login-Refactoring/assets/images/home_icon.svg b/clone-instagram-login-Refactoring/assets/images/home_icon.svg new file mode 100644 index 0000000..f6b1ffa --- /dev/null +++ b/clone-instagram-login-Refactoring/assets/images/home_icon.svg @@ -0,0 +1 @@ +icon instagram \ No newline at end of file diff --git a/clone-instagram-login-Refactoring/assets/images/love_active_icon.svg b/clone-instagram-login-Refactoring/assets/images/love_active_icon.svg new file mode 100644 index 0000000..04fefb6 --- /dev/null +++ b/clone-instagram-login-Refactoring/assets/images/love_active_icon.svg @@ -0,0 +1 @@ +like \ No newline at end of file diff --git a/clone-instagram-login-Refactoring/assets/images/love_icon.svg b/clone-instagram-login-Refactoring/assets/images/love_icon.svg new file mode 100644 index 0000000..3b65caf --- /dev/null +++ b/clone-instagram-login-Refactoring/assets/images/love_icon.svg @@ -0,0 +1 @@ +like \ No newline at end of file diff --git a/clone-instagram-login-Refactoring/assets/images/loved_icon.svg b/clone-instagram-login-Refactoring/assets/images/loved_icon.svg new file mode 100644 index 0000000..c70376e --- /dev/null +++ b/clone-instagram-login-Refactoring/assets/images/loved_icon.svg @@ -0,0 +1 @@ +like \ No newline at end of file diff --git a/clone-instagram-login-Refactoring/assets/images/message_icon.svg b/clone-instagram-login-Refactoring/assets/images/message_icon.svg new file mode 100644 index 0000000..2f96bc5 --- /dev/null +++ b/clone-instagram-login-Refactoring/assets/images/message_icon.svg @@ -0,0 +1 @@ +Untitled-1 \ No newline at end of file diff --git a/clone-instagram-login-Refactoring/assets/images/save_icon.svg b/clone-instagram-login-Refactoring/assets/images/save_icon.svg new file mode 100644 index 0000000..a141198 --- /dev/null +++ b/clone-instagram-login-Refactoring/assets/images/save_icon.svg @@ -0,0 +1 @@ +icon instagram \ No newline at end of file diff --git a/clone-instagram-login-Refactoring/assets/images/search_active_icon.svg b/clone-instagram-login-Refactoring/assets/images/search_active_icon.svg new file mode 100644 index 0000000..1d5b6b3 --- /dev/null +++ b/clone-instagram-login-Refactoring/assets/images/search_active_icon.svg @@ -0,0 +1,2 @@ + + diff --git a/clone-instagram-login-Refactoring/assets/images/search_icon.svg b/clone-instagram-login-Refactoring/assets/images/search_icon.svg new file mode 100644 index 0000000..6a1fd2f --- /dev/null +++ b/clone-instagram-login-Refactoring/assets/images/search_icon.svg @@ -0,0 +1 @@ +icon instagram \ No newline at end of file diff --git a/clone-instagram-login-Refactoring/assets/images/upload_active_icon.svg b/clone-instagram-login-Refactoring/assets/images/upload_active_icon.svg new file mode 100644 index 0000000..954ba39 --- /dev/null +++ b/clone-instagram-login-Refactoring/assets/images/upload_active_icon.svg @@ -0,0 +1 @@ +upload_icon \ No newline at end of file diff --git a/clone-instagram-login-Refactoring/assets/images/upload_icon.svg b/clone-instagram-login-Refactoring/assets/images/upload_icon.svg new file mode 100644 index 0000000..ec71556 --- /dev/null +++ b/clone-instagram-login-Refactoring/assets/images/upload_icon.svg @@ -0,0 +1 @@ +icon instagram \ No newline at end of file diff --git a/clone-instagram-login-Refactoring/assets/instagram_logo.png b/clone-instagram-login-Refactoring/assets/instagram_logo.png new file mode 100644 index 0000000..6b66c82 Binary files /dev/null and b/clone-instagram-login-Refactoring/assets/instagram_logo.png differ diff --git a/clone-instagram-login-Refactoring/integration_test/app_test.dart b/clone-instagram-login-Refactoring/integration_test/app_test.dart new file mode 100644 index 0000000..1ada004 --- /dev/null +++ b/clone-instagram-login-Refactoring/integration_test/app_test.dart @@ -0,0 +1,206 @@ +import 'package:example_widget_testing/app/modules/account/account_page.dart'; +import 'package:example_widget_testing/app/modules/activity/activity_page.dart'; +import 'package:example_widget_testing/app/modules/home/home_page.dart'; +import 'package:example_widget_testing/app/modules/login/login_page.dart'; +import 'package:example_widget_testing/app/modules/post/post_page.dart'; +import 'package:example_widget_testing/app/modules/search/search_page.dart'; +import 'package:example_widget_testing/app/modules/upload/upload_page.dart'; +import 'package:example_widget_testing/core/values/constant/post_json.dart'; +import 'package:example_widget_testing/core/values/constant/profile_json.dart'; +import 'package:example_widget_testing/core/values/constant/search_json.dart'; +import 'package:example_widget_testing/core/values/constant/story_json.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + var routes = { + '/login': (context) => const LoginPage(), + '/home': (context) => + HomePage(posts: posts, stories: stories, profileData: profileJson), + '/search': (context) => SearchPage(searchPosts: searchImages), + '/upload': (context) => const UploadPage(), + '/activity': (context) => const ActivityPage(), + '/account': (context) => + AccountPage(profileData: profileJson, posts: posts, stories: stories), + '/post': (context) => PostPage(posts: posts), + }; + + group('end-to-end test', () { + testWidgets('Change dropdown value', (tester) async { + await tester.pumpWidget(MaterialApp( + home: const LoginPage(), + routes: routes, + )); + + // find DropdownButton with key language_dropdown + final Finder dropdownButton = find.byKey(const Key('language_dropdown')); + + // expect DropdownButton is found + expect(dropdownButton, findsOneWidget); + + expect(find.text('English'), findsOneWidget); + + // tap on DropdownButton + await tester.tap(dropdownButton); + + // move to next frame + await tester.pumpAndSettle(); + + // find DropdownMenuItem with key language_dropdown_item_Arabic + final Finder dropdownMenuItem = + find.byKey(const Key("language_dropdown_item_Italian")); + + expect(dropdownMenuItem, findsNWidgets(2)); + + // tap on DropdownMenuItem + await tester.tap(dropdownMenuItem.last); + + // move to next frame + await tester.pumpAndSettle(); + + // expect find text Arabic + expect(find.text('Italian'), findsOneWidget); + }); + + testWidgets('Fill username and password then tap on login button', + (tester) async { + await tester.pumpWidget(MaterialApp( + home: const LoginPage(), + routes: routes, + )); + + // find TextField with key password_textfield + final Finder passwordTextField = + find.byKey(const Key('password_textfield')); + + // enter text into TextField + await tester.enterText(passwordTextField, 'test'); + + // find ElevatedButton with key login_button_elevated_button + final Finder loginButton = + find.byKey(const Key('login_button_elevated_button')); + + // tap on ElevatedButton + await tester.tap(loginButton); + + // expect nothing happen + await tester.pumpAndSettle(); + + // find AppBar with key home_page_appbar + final Finder appBar = find.byKey(const Key('home_page_appbar')); + + // check if AppBar is not found + expect(appBar, findsNothing); + }); + + testWidgets('Fill username and password then tap on login button', + (tester) async { + // Load app widget. + await tester.pumpWidget(MaterialApp( + home: const LoginPage(), + routes: routes, + )); + + // find TextField with key username_textfield + final Finder usernameTextField = + find.byKey(const Key('username_textfield')); + + // enter text into TextField + await tester.enterText(usernameTextField, 'test'); + + // find TextField with key password_textfield + final Finder passwordTextField = + find.byKey(const Key('password_textfield')); + + // enter text into TextField + await tester.enterText(passwordTextField, 'test'); + + // find ElevatedButton with key login_button_elevated_button + final Finder loginButton = + find.byKey(const Key('login_button_elevated_button')); + + // tap on ElevatedButton + await tester.tap(loginButton); + + // move to next frame + await tester.pumpAndSettle(); + + // find AppBar with key home_page_appbar + final Finder appBar = find.byKey(const Key('home_page_appbar')); + + // check if AppBar is found + expect(appBar, findsOneWidget); + }); + + testWidgets('Open home page then navigate to search page', (tester) async { + // Load app widget. + await tester.pumpWidget(MaterialApp( + home: HomePage( + posts: posts, + stories: stories, + profileData: profileJson, + ), + routes: routes, + )); + + // scroll to bottom + await tester.fling( + find.byKey(const Key('home_page_single_child_scroll_view')), + const Offset(0, 300), + 1000, + ); + + // find search icon in bottom navbar + final Finder searchIcon = find.byKey(const Key('bottom_item_1')); + + // tap on search icon + await tester.tap(searchIcon); + + // move to next frame + await tester.pumpAndSettle(const Duration(seconds: 5)); + + // navigate to search page + expect(find.byKey(const Key('search_page_app_bar_preferred_size')), + findsOneWidget); + + // find search up icon in search page + final Finder uploadIcon = find.byKey(const Key('bottom_item_2')); + + // tap on upload icon + await tester.tap(uploadIcon); + + // move to next frame + await tester.pumpAndSettle(); + + // navigate to upload page + expect(find.byKey(const Key('upload_page_appbar')), findsOneWidget); + + // find activity icon in bottom navbar + final Finder activityIcon = find.byKey(const Key('bottom_item_3')); + + // tap on activity icon + await tester.tap(activityIcon); + + // move to next frame + await tester.pumpAndSettle(); + + // navigate to activity page + expect(find.byKey(const Key('activity_page_appbar')), findsOneWidget); + + // find account icon in bottom navbar + final Finder accountIcon = find.byKey(const Key('bottom_item_4')); + + // tap on account icon + await tester.tap(accountIcon); + + // move to next frame + await tester.pumpAndSettle(); + + // navigate to account page + expect(find.byKey(const Key('app_bar_account')), findsOneWidget); + }); + }); +} diff --git a/clone-instagram-login-Refactoring/integration_test/calculator_test.dart b/clone-instagram-login-Refactoring/integration_test/calculator_test.dart new file mode 100644 index 0000000..ba8b78b --- /dev/null +++ b/clone-instagram-login-Refactoring/integration_test/calculator_test.dart @@ -0,0 +1,61 @@ +import 'package:example_widget_testing/app/modules/calculator.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + group('end-to-end test', () { + testWidgets('Change dropdown value', (tester) async { + await tester.pumpWidget( + const MaterialApp( + home: SimpleCalculator(), + ), + ); + + const variableA = '2'; + const variableB = '3'; + const result = '5'; + + // find text field with key variableA + final Finder variableAField = find.byKey(const Key('variableA')); + + // expect text field is found + expect(variableAField, findsOneWidget); + + // find text field with key variableB + final Finder variableBField = find.byKey(const Key('variableB')); + + // expect text field is found + expect(variableBField, findsOneWidget); + + // enter text 2 + await tester.enterText(variableAField, variableA); + + // enter text 3 + await tester.enterText(variableBField, variableB); + + // find button with key addButton + final Finder addButton = find.byKey(const Key('addButton')); + + // expect button is found + expect(addButton, findsOneWidget); + + // tap on button + await tester.tap(addButton); + + // move to next frame + await tester.pumpAndSettle(); + + // find text with key result + final Finder resultTextFinder = find.byKey(const Key('result')); + + // expect text is found + expect(resultTextFinder, findsOneWidget); + + // expect text is 5 + expect(find.text(result), findsOneWidget); + }); + }); +} diff --git a/clone-instagram-login-Refactoring/ios/.gitignore b/clone-instagram-login-Refactoring/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/clone-instagram-login-Refactoring/ios/Flutter/AppFrameworkInfo.plist b/clone-instagram-login-Refactoring/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..9625e10 --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 11.0 + + diff --git a/clone-instagram-login-Refactoring/ios/Flutter/Debug.xcconfig b/clone-instagram-login-Refactoring/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/clone-instagram-login-Refactoring/ios/Flutter/Release.xcconfig b/clone-instagram-login-Refactoring/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/clone-instagram-login-Refactoring/ios/Runner.xcodeproj/project.pbxproj b/clone-instagram-login-Refactoring/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..1d56de4 --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,481 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.exampleWidgetTesting; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.exampleWidgetTesting; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.exampleWidgetTesting; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/clone-instagram-login-Refactoring/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/clone-instagram-login-Refactoring/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/clone-instagram-login-Refactoring/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/clone-instagram-login-Refactoring/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/clone-instagram-login-Refactoring/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/clone-instagram-login-Refactoring/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/clone-instagram-login-Refactoring/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/clone-instagram-login-Refactoring/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..c87d15a --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/clone-instagram-login-Refactoring/ios/Runner.xcworkspace/contents.xcworkspacedata b/clone-instagram-login-Refactoring/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/clone-instagram-login-Refactoring/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/clone-instagram-login-Refactoring/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/clone-instagram-login-Refactoring/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/clone-instagram-login-Refactoring/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/clone-instagram-login-Refactoring/ios/Runner/AppDelegate.swift b/clone-instagram-login-Refactoring/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..70693e4 --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..dc9ada4 Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..28c6bf0 Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..f091b6b Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cde121 Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..d0ef06e Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..dcdc230 Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..c8f9ed8 Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..a6d6b86 Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..a6d6b86 Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..75b2d16 Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..c4df70d Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..6a84f41 Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..d0e1f58 Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +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. \ No newline at end of file diff --git a/clone-instagram-login-Refactoring/ios/Runner/Base.lproj/LaunchScreen.storyboard b/clone-instagram-login-Refactoring/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/clone-instagram-login-Refactoring/ios/Runner/Base.lproj/Main.storyboard b/clone-instagram-login-Refactoring/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/clone-instagram-login-Refactoring/ios/Runner/Info.plist b/clone-instagram-login-Refactoring/ios/Runner/Info.plist new file mode 100644 index 0000000..5dfe479 --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner/Info.plist @@ -0,0 +1,51 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Example Widget Testing + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + example_widget_testing + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/clone-instagram-login-Refactoring/ios/Runner/Runner-Bridging-Header.h b/clone-instagram-login-Refactoring/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/clone-instagram-login-Refactoring/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/clone-instagram-login-Refactoring/lib/app/data/models/navbar_menu.dart b/clone-instagram-login-Refactoring/lib/app/data/models/navbar_menu.dart new file mode 100644 index 0000000..eba0bd9 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/data/models/navbar_menu.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; + +class NavbarMenu { + int? id; + String? name; + String? activeIcon; + String? inactiveIcon; + String? path; + Widget? widget; + + NavbarMenu( + {this.id, this.name, this.activeIcon, this.inactiveIcon, this.path}); + + NavbarMenu.fromJson(Map json) { + id = json['id']; + name = json['name']; + activeIcon = json['active_icon']; + inactiveIcon = json['inactive_icon']; + path = json['path']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + data['active_icon'] = activeIcon; + data['inactive_icon'] = inactiveIcon; + data['path'] = path; + return data; + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/data/models/post.dart b/clone-instagram-login-Refactoring/lib/app/data/models/post.dart new file mode 100644 index 0000000..f7f3f6f --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/data/models/post.dart @@ -0,0 +1,48 @@ +class Post { + int? id; + String? name; + String? profileImg; + String? postImg; + String? caption; + bool? isLoved; + String? commentCount; + String? likedBy; + String? timeAgo; + + Post( + {this.id, + this.name, + this.profileImg, + this.postImg, + this.caption, + this.isLoved, + this.commentCount, + this.likedBy, + this.timeAgo}); + + Post.fromJson(Map json) { + id = json['id']; + name = json['name']; + profileImg = json['profileImg']; + postImg = json['postImg']; + caption = json['caption']; + isLoved = json['isLoved']; + commentCount = json['commentCount']; + likedBy = json['likedBy']; + timeAgo = json['timeAgo']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + data['profileImg'] = profileImg; + data['postImg'] = postImg; + data['caption'] = caption; + data['isLoved'] = isLoved; + data['commentCount'] = commentCount; + data['likedBy'] = likedBy; + data['timeAgo'] = timeAgo; + return data; + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/data/models/profile.dart b/clone-instagram-login-Refactoring/lib/app/data/models/profile.dart new file mode 100644 index 0000000..2ee7c58 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/data/models/profile.dart @@ -0,0 +1,50 @@ +class Profile { + String? name; + String? bio; + String? profilePic; + List? stats; + + Profile({this.name, this.bio, this.profilePic, this.stats}); + + Profile.fromJson(Map json) { + name = json['name']; + bio = json['bio']; + profilePic = json['profilePic']; + if (json['stats'] != null) { + stats = []; + json['stats'].forEach((v) { + stats!.add(Stats.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + data['name'] = name; + data['bio'] = bio; + data['profilePic'] = profilePic; + if (stats != null) { + data['stats'] = stats!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class Stats { + int? count; + String? label; + + Stats({this.count, this.label}); + + Stats.fromJson(Map json) { + count = json['count']; + label = json['label']; + } + + Map toJson() { + final Map data = {}; + data['count'] = count; + data['label'] = label; + return data; + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/account/account_page.dart b/clone-instagram-login-Refactoring/lib/app/modules/account/account_page.dart new file mode 100644 index 0000000..e80f4f5 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/account/account_page.dart @@ -0,0 +1,116 @@ +import 'package:example_widget_testing/app/modules/account/components/account_name.dart'; +import 'package:example_widget_testing/app/modules/account/components/account_tab.dart'; +import 'package:example_widget_testing/app/modules/account/components/highlight_list.dart'; +import 'package:example_widget_testing/app/modules/account/components/profile_buttons.dart'; +import 'package:example_widget_testing/app/widgets/bottom_navbar.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import '../../data/models/profile.dart'; +import '../../widgets/post_thumbnail.dart'; +import 'components/account_stat.dart'; + +class AccountPage extends StatefulWidget { + const AccountPage( + {super.key, + required this.profileData, + required this.posts, + required this.stories}); + final Map profileData; + final List posts; + final List stories; + + @override + AccountPageState createState() => AccountPageState(); +} + +class AccountPageState extends State { + int pageIndex = 0; + + void updateIndex(int index) { + setState(() => pageIndex = index); + } + + @override + Widget build(BuildContext context) { + final Profile profile = Profile.fromJson(widget.profileData); + return Scaffold( + backgroundColor: Colors.black, + appBar: AppBar( + key: const Key('app_bar_account'), + backgroundColor: Colors.black, + automaticallyImplyLeading: false, + title: Row( + key: const Key('app_bar_row'), + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + key: const Key('app_bar_row_name'), + children: const [ + Text( + key: Key('app_bar_row_name_text'), + "iclop", + style: TextStyle(fontWeight: FontWeight.bold), + ), + Icon( + key: Key('app_bar_row_name_arrow_down_icon'), + Icons.keyboard_arrow_down, + ), + ], + ), + Row( + key: const Key('app_bar_row_menu'), + children: [ + SvgPicture.asset( + key: const Key('app_bar_row_menu_upload_icon'), + "assets/images/upload_icon.svg", + width: 27, + ), + const SizedBox( + width: 10, + ), + const Icon( + key: Key('app_bar_row_menu_hamburger_icon'), + Icons.menu, + size: 35, + ), + ], + ) + ], + ), + ), + body: ListView( + key: const Key('account_page_listview'), + children: [ + AccountStat(key: const Key("account_stat"), profile: profile), + AccountName(key: const Key("account_name"), profile: profile), + const ProfileButtons(key: Key("profile_buttons")), + HighlightList( + key: const Key("highlight_list"), stories: widget.stories), + AccountTab( + key: const Key("account_tab"), + updateIndex: updateIndex, + pageIndex: pageIndex, + ), + Wrap( + key: const Key('account_page_post_wrap'), + spacing: 1.5, + runSpacing: 1.5, + children: List.generate(widget.posts.length, (index) { + return InkWell( + key: Key("account_post_inkwell_$index"), + onTap: () { + Navigator.pushNamed(context, '/post'); + }, + child: PostThumbnail( + key: Key("account_post_thumbnail_$index"), + imageUrl: widget.posts[index]['postImg'], + ), + ); + }), + ) + ], + ), + bottomNavigationBar: const BottomNavbar(pageIndex: 4), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/account/components/account_name.dart b/clone-instagram-login-Refactoring/lib/app/modules/account/components/account_name.dart new file mode 100644 index 0000000..f3a8fd5 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/account/components/account_name.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; + +import '../../../data/models/profile.dart'; + +class AccountName extends StatelessWidget { + const AccountName({super.key, required this.profile}); + final Profile profile; + + @override + Widget build(BuildContext context) { + return Container( + key: const Key('account_name_container'), + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 15), + margin: const EdgeInsets.symmetric(vertical: 10), + child: Column( + key: const Key('account_name_column'), + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + key: const Key('account_name_text'), + profile.name!, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w400, + color: Colors.white, + ), + ), + Text( + key: const Key('account_bio_text'), + profile.bio!, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w400, + color: Colors.white, + ), + ), + ], + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/account/components/account_stat.dart b/clone-instagram-login-Refactoring/lib/app/modules/account/components/account_stat.dart new file mode 100644 index 0000000..0db3a23 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/account/components/account_stat.dart @@ -0,0 +1,31 @@ +import 'package:example_widget_testing/app/modules/account/components/profile_information.dart'; +import 'package:example_widget_testing/app/modules/account/components/profile_pic.dart'; +import 'package:flutter/widgets.dart'; + +import '../../../data/models/profile.dart'; + +class AccountStat extends StatelessWidget { + final Profile profile; + + const AccountStat({super.key, required this.profile}); + + @override + Widget build(BuildContext context) { + return Row( + key: const Key('account_page_profile_row'), + children: [ + ProfilePic( + key: const Key("profile_pic"), + pictureUrl: profile.profilePic!, + ), + Expanded( + key: const Key('account_page_profile_information_expanded'), + child: ProfileInformation( + key: const Key("profile_information"), + profileStats: profile.stats!, + ), + ), + ], + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/account/components/account_tab.dart b/clone-instagram-login-Refactoring/lib/app/modules/account/components/account_tab.dart new file mode 100644 index 0000000..53b416c --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/account/components/account_tab.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; + +import '../../../../core/values/constant/profile_tabs_json.dart'; + +class AccountTab extends StatelessWidget { + final Function(int index) updateIndex; + final int pageIndex; + + const AccountTab( + {super.key, required this.updateIndex, required this.pageIndex}); + + @override + Widget build(BuildContext context) { + final size = MediaQuery.of(context).size; + return Row( + key: const Key("account_tab_row"), + children: List.generate( + tabs.length, + (index) { + return DecoratedBox( + key: Key('account_tab_decorated_box_$index'), + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: pageIndex == index ? Colors.white : Colors.transparent, + width: 2, + ), + ), + ), + child: ElevatedButton( + key: Key('account_tab_elevated_button_$index'), + onPressed: () => updateIndex(index), + style: ElevatedButton.styleFrom( + elevation: 0, + backgroundColor: Colors.transparent, + minimumSize: Size(size.width / tabs.length, 40), + ), + child: Icon( + tabs[index]['icon'], + key: Key('account_tab_icon_$index'), + color: Colors.white, + ), + ), + ); + }, + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/account/components/grey_button.dart b/clone-instagram-login-Refactoring/lib/app/modules/account/components/grey_button.dart new file mode 100644 index 0000000..3b4c318 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/account/components/grey_button.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; + +class GreyButton extends StatelessWidget { + final Function onPressed; + final Widget child; + + const GreyButton({super.key, required this.onPressed, required this.child}); + @override + Widget build(BuildContext context) { + return ElevatedButton( + key: Key('${key}_elevated_button'), + onPressed: () => {}, + style: ElevatedButton.styleFrom( + minimumSize: const Size(0, 30), + backgroundColor: Colors.grey[800], + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5), + ), + ), + child: child, + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/account/components/highlight_item.dart b/clone-instagram-login-Refactoring/lib/app/modules/account/components/highlight_item.dart new file mode 100644 index 0000000..0c6177a --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/account/components/highlight_item.dart @@ -0,0 +1,58 @@ +import 'package:example_widget_testing/core/theme/colors.dart'; +import 'package:flutter/material.dart'; + +class HighlightItem extends StatelessWidget { + final String img; + final String name; + + const HighlightItem({super.key, required this.img, required this.name}); + + @override + Widget build(BuildContext context) { + return Padding( + key: const Key('highlight_item_padding'), + padding: const EdgeInsets.only(right: 10, bottom: 10), + child: Column( + key: const Key('highlight_item_column'), + children: [ + Container( + key: const Key('highlight_item_container'), + width: 68, + height: 68, + padding: const EdgeInsets.all(3.0), + margin: const EdgeInsets.only(bottom: 8), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: (Colors.grey[800])!, + width: 1, + ), + ), + child: Container( + key: const Key('highlight_item_image_container'), + decoration: BoxDecoration( + border: Border.all(color: Colors.black, width: 2), + shape: BoxShape.circle, + image: DecorationImage( + image: NetworkImage(img), + fit: BoxFit.cover, + ), + ), + ), + ), + SizedBox( + key: const Key('highlight_item_text_sized_box'), + width: 70, + child: Text( + key: const Key('highlight_item_text'), + name, + overflow: TextOverflow.ellipsis, + style: const TextStyle(color: white), + textAlign: TextAlign.center, + ), + ) + ], + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/account/components/highlight_list.dart b/clone-instagram-login-Refactoring/lib/app/modules/account/components/highlight_list.dart new file mode 100644 index 0000000..eafecca --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/account/components/highlight_list.dart @@ -0,0 +1,81 @@ +import 'package:example_widget_testing/app/modules/account/components/highlight_item.dart'; +import 'package:flutter/material.dart'; + +class HighlightList extends StatelessWidget { + const HighlightList({super.key, required this.stories}); + final List stories; + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + key: const Key('highlight_list_scroll_view'), + padding: const EdgeInsets.only(left: 15, top: 10, bottom: 10), + scrollDirection: Axis.horizontal, + child: Row( + key: const Key('highlight_list_parent_row'), + children: [ + Row( + key: const Key('highlight_list_child_row'), + children: List.generate( + stories.length, + (index) { + return HighlightItem( + key: Key('highlight_item_$index'), + img: stories[index]['img'], + name: stories[index]['name'], + ); + }, + ), + ), + Padding( + key: const Key('highlight_list_add_highlight'), + padding: const EdgeInsets.only(right: 10, bottom: 10), + child: Column( + key: const Key('highlight_list_add_highlight_column'), + children: [ + Container( + key: const Key('highlight_list_add_highlight_container'), + width: 68, + height: 68, + padding: const EdgeInsets.all(3.0), + margin: const EdgeInsets.only(bottom: 8), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: Colors.white, + width: 1, + ), + ), + child: Container( + key: const Key( + 'highlight_list_add_highlight_icon_container'), + decoration: BoxDecoration( + border: Border.all(color: Colors.black, width: 2), + shape: BoxShape.circle, + ), + child: const Icon( + key: Key('highlight_list_add_highlight_icon'), + Icons.add, + color: Colors.white, + ), + ), + ), + const SizedBox( + key: Key('highlight_list_add_highlight_text_sized_box'), + width: 70, + child: Text( + key: Key('highlight_list_add_highlight_text'), + 'New', + overflow: TextOverflow.ellipsis, + style: TextStyle(color: Colors.white), + textAlign: TextAlign.center, + ), + ) + ], + ), + ), + ], + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/account/components/profile_buttons.dart b/clone-instagram-login-Refactoring/lib/app/modules/account/components/profile_buttons.dart new file mode 100644 index 0000000..32c9322 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/account/components/profile_buttons.dart @@ -0,0 +1,63 @@ +import 'package:example_widget_testing/app/modules/account/components/grey_button.dart'; +import 'package:flutter/material.dart'; + +class ProfileButtons extends StatelessWidget { + const ProfileButtons({super.key}); + + @override + Widget build(BuildContext context) { + return Padding( + key: const Key('profile_buttons_padding'), + padding: const EdgeInsets.symmetric(horizontal: 15), + child: Row( + key: const Key('profile_buttons_row'), + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + key: const Key('profile_buttons_edit_profile_button_expanded'), + child: GreyButton( + key: const Key('profile_buttons_edit_profile_button'), + onPressed: () {}, + child: const Text( + key: Key('profile_buttons_edit_profile_button_text'), + "Edit Profile", + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + ), + ), + ), + const SizedBox(width: 5), + Expanded( + key: const Key('profile_buttons_share_profile_button_expanded'), + child: GreyButton( + key: const Key('profile_buttons_share_profile_button'), + onPressed: () {}, + child: const Text( + key: Key('profile_buttons_share_profile_button_text'), + "Share profile", + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + ), + ), + ), + const SizedBox(width: 5), + GreyButton( + key: const Key('profile_buttons_discover_people_button'), + onPressed: () {}, + child: const Icon( + key: Key("profile_buttons_discover_people_icon"), + Icons.person_add_outlined, + color: Colors.white, + ), + ), + ], + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/account/components/profile_information.dart b/clone-instagram-login-Refactoring/lib/app/modules/account/components/profile_information.dart new file mode 100644 index 0000000..c2e769f --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/account/components/profile_information.dart @@ -0,0 +1,43 @@ +import 'package:example_widget_testing/app/data/models/profile.dart'; +import 'package:flutter/material.dart'; + +class ProfileInformation extends StatelessWidget { + const ProfileInformation({super.key, required this.profileStats}); + final List profileStats; + + @override + Widget build(BuildContext context) { + return Row( + key: const Key('profile_information_row'), + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: List.generate( + profileStats.length, + (index) { + return Column( + key: Key('profile_information_column_$index'), + children: [ + Text( + key: Key('profile_information_${index}_amount_text'), + profileStats[index].count.toString(), + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.w700, + color: Colors.white, + ), + ), + Text( + profileStats[index].label!, + key: Key('profile_information_${index}_label_text'), + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w400, + color: Colors.white, + ), + ), + ], + ); + }, + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/account/components/profile_pic.dart b/clone-instagram-login-Refactoring/lib/app/modules/account/components/profile_pic.dart new file mode 100644 index 0000000..c7fa599 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/account/components/profile_pic.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; + +class ProfilePic extends StatelessWidget { + const ProfilePic({super.key, required this.pictureUrl}); + final String pictureUrl; + + @override + Widget build(BuildContext context) { + return Container( + key: const Key('profile_pic_container'), + width: 80, + height: 80, + margin: const EdgeInsets.only(left: 15, right: 30), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: NetworkImage(pictureUrl), + fit: BoxFit.cover, + ), + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/account/components/tab_delegate.dart b/clone-instagram-login-Refactoring/lib/app/modules/account/components/tab_delegate.dart new file mode 100644 index 0000000..00495e1 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/account/components/tab_delegate.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; + +class MyPersistentHeaderDelegate extends SliverPersistentHeaderDelegate { + final double height; + final Widget child; + + MyPersistentHeaderDelegate({ + required this.height, + required this.child, + }); + + @override + Widget build( + BuildContext context, double shrinkOffset, bool overlapsContent) { + return Container( + color: Colors.white, // Set the background color of the header + height: height, + child: child, + ); + } + + @override + double get maxExtent => height; + + @override + double get minExtent => height; + + @override + bool shouldRebuild(covariant MyPersistentHeaderDelegate oldDelegate) { + return height != oldDelegate.height || child != oldDelegate.child; + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/activity/activity_page.dart b/clone-instagram-login-Refactoring/lib/app/modules/activity/activity_page.dart new file mode 100644 index 0000000..bb4cad5 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/activity/activity_page.dart @@ -0,0 +1,40 @@ +import 'package:example_widget_testing/app/widgets/bottom_navbar.dart'; +import 'package:flutter/material.dart'; + +class ActivityPage extends StatelessWidget { + const ActivityPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.black, + appBar: AppBar( + key: const Key("activity_page_appbar"), + backgroundColor: Colors.black, + title: const Text("Activity"), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + Icon( + Icons.favorite_border, + color: Colors.white, + size: 100.0, + ), + SizedBox(height: 20.0), + Text( + "No Activity", + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + ], + ), + ), + bottomNavigationBar: const BottomNavbar(pageIndex: 3), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/calculator.dart b/clone-instagram-login-Refactoring/lib/app/modules/calculator.dart new file mode 100644 index 0000000..2d9845f --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/calculator.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; + +class SimpleCalculator extends StatefulWidget { + const SimpleCalculator({Key? key}) : super(key: key); + + @override + State createState() => SimpleCalculatorState(); +} + +class SimpleCalculatorState extends State { + TextEditingController variableA = TextEditingController(); + TextEditingController variableB = TextEditingController(); + String result = '0'; + + void add() { + setState(() { + result = + (int.parse(variableA.text) + int.parse(variableB.text)).toString(); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Simple Calculator')), + body: Padding( + padding: const EdgeInsets.all(10), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextField( + key: const Key('variableA'), + style: const TextStyle(color: Colors.black), + decoration: const InputDecoration( + border: OutlineInputBorder(), + ), + controller: variableA, + keyboardType: TextInputType.number, + ), + const SizedBox(height: 10), + TextField( + key: const Key('variableB'), + // add border + style: const TextStyle(color: Colors.black), + decoration: const InputDecoration( + border: OutlineInputBorder(), + ), + controller: variableB, + keyboardType: TextInputType.number, + ), + ElevatedButton( + key: const Key('addButton'), + onPressed: () => add(), + child: const Text('Add'), + ), + Text( + key: const Key('result'), + result, + style: const TextStyle(fontSize: 35), + ), + ], + ), + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/home/components/story_item.dart b/clone-instagram-login-Refactoring/lib/app/modules/home/components/story_item.dart new file mode 100644 index 0000000..287ad74 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/home/components/story_item.dart @@ -0,0 +1,63 @@ +import 'package:example_widget_testing/core/theme/colors.dart'; +import 'package:flutter/material.dart'; + +class StoryItem extends StatelessWidget { + final String img; + final String name; + + const StoryItem({ + super.key, + required this.img, + required this.name, + }); + + @override + Widget build(BuildContext context) { + return Padding( + key: const Key('story_item_padding'), + padding: const EdgeInsets.only(right: 20, bottom: 10), + child: Column( + key: const Key('story_item_column'), + children: [ + Container( + key: const Key('story_item_container'), + width: 68, + height: 68, + margin: const EdgeInsets.only(bottom: 8), + decoration: const BoxDecoration( + shape: BoxShape.circle, + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: storyBorderColor), + ), + child: Container( + key: const Key('story_item_image_container'), + margin: const EdgeInsets.all(3), + width: 65, + height: 65, + decoration: BoxDecoration( + border: Border.all(color: black, width: 2), + shape: BoxShape.circle, + image: DecorationImage( + image: NetworkImage(img), + fit: BoxFit.cover, + ), + ), + ), + ), + SizedBox( + key: const Key('story_item_username_sizedbox'), + width: 70, + child: Text( + name, + key: const Key('story_item_username_text'), + overflow: TextOverflow.ellipsis, + style: const TextStyle(color: white), + ), + ) + ], + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/home/components/user_story.dart b/clone-instagram-login-Refactoring/lib/app/modules/home/components/user_story.dart new file mode 100644 index 0000000..de68441 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/home/components/user_story.dart @@ -0,0 +1,76 @@ +import 'package:example_widget_testing/core/theme/colors.dart'; +import 'package:example_widget_testing/core/values/constant/story_json.dart'; +import 'package:flutter/material.dart'; + +class UserStory extends StatelessWidget { + const UserStory({super.key}); + + @override + Widget build(BuildContext context) { + return Padding( + key: const Key('user_story_padding'), + padding: const EdgeInsets.only(right: 20, left: 15, bottom: 10), + child: Column( + key: const Key('user_story_column'), + children: [ + SizedBox( + key: const Key('user_story_sized_box'), + width: 65, + height: 65, + child: Stack( + key: const Key('user_story_stack'), + children: [ + Container( + key: const Key('user_story_container'), + width: 65, + height: 65, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: NetworkImage(profile), + fit: BoxFit.cover, + ), + ), + ), + Positioned( + key: const Key('user_story_positioned'), + bottom: 0, + right: 0, + child: Container( + key: const Key('user_story_outline_container'), + width: 19, + height: 19, + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Colors.white, + ), + child: const Icon( + key: Key('user_story_add_circle_icon'), + Icons.add_circle, + color: buttonFollowColor, + size: 19, + ), + ), + ) + ], + ), + ), + const SizedBox( + key: Key('user_story_sized_box_spacer'), + height: 8, + ), + SizedBox( + key: const Key('user_story_sized_box_name'), + width: 70, + child: Text( + key: const Key('user_story_text_name'), + name, + overflow: TextOverflow.ellipsis, + style: const TextStyle(color: Colors.white), + ), + ) + ], + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/home/home_page.dart b/clone-instagram-login-Refactoring/lib/app/modules/home/home_page.dart new file mode 100644 index 0000000..0a903a8 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/home/home_page.dart @@ -0,0 +1,126 @@ +import 'package:example_widget_testing/app/modules/home/components/user_story.dart'; +import 'package:example_widget_testing/app/widgets/post_item.dart'; +import 'package:example_widget_testing/app/modules/home/components/story_item.dart'; +import 'package:flutter/material.dart'; + +import '../../../core/theme/colors.dart'; +import '../../data/models/profile.dart'; +import '../../widgets/bottom_navbar.dart'; + +class HomePage extends StatefulWidget { + const HomePage({ + super.key, + required this.posts, + required this.stories, + required this.profileData, + }); + final List posts; + final List stories; + final Map profileData; + + @override + HomePageState createState() => HomePageState(); +} + +class HomePageState extends State { + List posts = []; + @override + void initState() { + super.initState(); + posts = widget.posts; + } + + void updatePostLike(index) { + setState(() { + posts[index]['isLoved'] = !posts[index]['isLoved']; + }); + } + + @override + Widget build(BuildContext context) { + final Profile profile = Profile.fromJson(widget.profileData); + return Scaffold( + key: const Key('home_page_scaffold'), + backgroundColor: Colors.black, + appBar: AppBar( + key: const Key("home_page_appbar"), + backgroundColor: Colors.black, + leading: const Icon( + key: Key('home_page_camera_icon'), + Icons.camera_alt, + ), + title: const Center( + key: Key('home_page_title_center'), + child: Text( + key: Key('home_page_title_text'), + "Instagram", + style: TextStyle(fontFamily: 'Billabong', fontSize: 35), + ), + ), + actions: const [ + Icon(key: Key('home_page_send_icon'), Icons.send), + ], + ), + body: SingleChildScrollView( + key: const Key('home_page_single_child_scroll_view'), + child: Column( + key: const Key('home_page_column'), + children: [ + SingleChildScrollView( + key: const Key('stories_scroll_view'), + scrollDirection: Axis.horizontal, + child: Row( + key: const Key('stories_row'), + children: [ + const UserStory(key: Key('user_story')), + Row( + key: const Key('following_stories_row'), + children: List.generate( + widget.stories.length, + (index) { + return StoryItem( + key: Key('story_item_$index'), + img: widget.stories[index]['img'], + name: widget.stories[index]['name'], + ); + }, + ), + ), + ], + ), + ), + Divider( + key: const Key('home_page_divider'), + color: white.withOpacity(0.3), + ), + Column( + key: const Key('posts_column'), + children: List.generate( + widget.posts.length, + (index) { + return PostItem( + key: Key('post_item_$index'), + postImg: posts[index]['postImg'], + profileImg: posts[index]['profileImg'], + name: posts[index]['name'], + caption: posts[index]['caption'], + isLoved: posts[index]['isLoved'], + viewCount: posts[index]['commentCount'], + likedBy: posts[index]['likedBy'], + dayAgo: posts[index]['timeAgo'], + userPhoto: profile.profilePic!, + onPressed: () => updatePostLike(index), + ); + }, + ), + ) + ], + ), + ), + bottomNavigationBar: const BottomNavbar( + key: Key('home_page_bottom_navbar'), + pageIndex: 0, + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/login/components/facebook_login.dart b/clone-instagram-login-Refactoring/lib/app/modules/login/components/facebook_login.dart new file mode 100644 index 0000000..63ad0d5 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/login/components/facebook_login.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +class FacebookLogin extends StatelessWidget { + final double width; + const FacebookLogin({super.key, required this.width}); + @override + Widget build(BuildContext context) { + return Row( + key: const Key('facebook_login'), + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/facebook.png', + height: width * .060, + key: const Key('facebook_logo'), + ), + const SizedBox(width: 5), + Text( + 'Login with facebook', + key: const Key('facebook_login_text'), + style: TextStyle( + color: const Color(0xff1877f2), + fontSize: width * .040, + fontWeight: FontWeight.w800, + ), + ), + ], + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/login/components/forgot_access.dart b/clone-instagram-login-Refactoring/lib/app/modules/login/components/forgot_access.dart new file mode 100644 index 0000000..8cd99e0 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/login/components/forgot_access.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; + +class ForgotAccess extends StatelessWidget { + final double width; + const ForgotAccess({super.key, required this.width}); + + @override + Widget build(BuildContext context) { + return Row( + key: const Key('forgot_access_row'), + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'Forgot your login details? ', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.normal, + color: Colors.black, + ), + key: Key('forgot_access_text'), + ), + GestureDetector( + key: const Key('get_help_gesture_detector'), + onTap: () { + debugPrint('Get help'); + }, + child: const Text( + 'Get help', + style: TextStyle( + fontSize: 13, + color: Color(0xff002588), + fontWeight: FontWeight.bold, + ), + key: Key('get_help_text'), + ), + ), + ], + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/login/components/language_dropdown.dart b/clone-instagram-login-Refactoring/lib/app/modules/login/components/language_dropdown.dart new file mode 100644 index 0000000..c885717 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/login/components/language_dropdown.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; + +class LanguageDropdown extends StatefulWidget { + const LanguageDropdown({super.key}); + + @override + LanguageDropdownState createState() => LanguageDropdownState(); +} + +class LanguageDropdownState extends State { + String dropdownValue = 'English'; + final List languages = ['English', 'Arabic', 'Italian', 'French']; + @override + Widget build(BuildContext context) { + return DropdownButton( + key: const Key('language_dropdown'), + dropdownColor: Colors.white, + value: dropdownValue, + icon: const Icon(Icons.arrow_drop_down), + iconSize: 24, + elevation: 10, + style: const TextStyle(color: Colors.black54), + underline: Container(), + onChanged: (String? newValue) => + setState(() => dropdownValue = newValue!), + items: languages.map>((String value) { + return DropdownMenuItem( + key: Key('language_dropdown_item_$value'), + value: value, + child: Text( + value, + style: const TextStyle(fontSize: 16), + ), + ); + }).toList(), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/login/components/login_button.dart b/clone-instagram-login-Refactoring/lib/app/modules/login/components/login_button.dart new file mode 100644 index 0000000..c6fb3b1 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/login/components/login_button.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; + +class LoginButton extends StatelessWidget { + final double width; + final bool inputTextNotNull; + final VoidCallback onPressed; + + const LoginButton({ + super.key, + required this.width, + required this.inputTextNotNull, + required this.onPressed, + }); + + @override + Widget build(BuildContext context) { + return SizedBox( + key: const Key('login_button_sized_box'), + width: width * .90, + height: width * .14, + child: ElevatedButton( + key: const Key('login_button_elevated_button'), + onPressed: onPressed, + style: ElevatedButton.styleFrom( + backgroundColor: inputTextNotNull + ? const Color(0xff26A9FF) + : const Color(0xff78C9FF), + ), + child: Text( + key: const Key('login_button_text'), + 'Log In', + style: TextStyle( + color: Colors.white, + fontSize: width * .040, + fontWeight: FontWeight.bold, + ), + ), + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/login/components/or_divider.dart b/clone-instagram-login-Refactoring/lib/app/modules/login/components/or_divider.dart new file mode 100644 index 0000000..05b16cb --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/login/components/or_divider.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; + +class ORDivider extends StatelessWidget { + final double width; + const ORDivider({super.key, required this.width}); + @override + Widget build(BuildContext context) { + return Row( + key: const Key('or_divider_row'), + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + key: const Key('or_divider_container_left'), + height: 1, + width: width * .40, + color: const Color(0xffA2A2A2), + ), + const SizedBox( + width: 10, + ), + Text( + key: const Key('or_divider_text'), + 'OR', + style: TextStyle( + fontSize: width * .040, + ), + ), + const SizedBox( + width: 10, + ), + Container( + key: const Key('or_divider_container_right'), + height: 1, + width: width * .40, + color: const Color(0xffA2A2A2), + ), + ], + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/login/components/password_textbox.dart b/clone-instagram-login-Refactoring/lib/app/modules/login/components/password_textbox.dart new file mode 100644 index 0000000..6ef86dd --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/login/components/password_textbox.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +class PasswordTextbox extends StatelessWidget { + const PasswordTextbox({ + super.key, + required this.width, + required this.checkInputNotNull, + required this.passwordController, + }); + + final double width; + final TextEditingController passwordController; + final VoidCallback checkInputNotNull; + @override + Widget build(BuildContext context) { + return Container( + key: const Key('password_textbox_container'), + width: width * .90, + height: width * .14, + decoration: const BoxDecoration( + color: Color(0xffE8E8E8), + borderRadius: BorderRadius.all(Radius.circular(5)), + ), + child: Padding( + key: const Key('password_textbox_padding'), + padding: const EdgeInsets.symmetric(horizontal: 15), + child: Center( + child: TextField( + key: const Key('password_textfield'), + onChanged: (text) { + checkInputNotNull(); + }, + controller: passwordController, + obscureText: true, + style: const TextStyle( + fontSize: 15, + ), + decoration: const InputDecoration.collapsed( + hintText: 'Password', + ), + ), + ), + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/login/components/signup_section.dart b/clone-instagram-login-Refactoring/lib/app/modules/login/components/signup_section.dart new file mode 100644 index 0000000..bea18a1 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/login/components/signup_section.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; + +class SignupSection extends StatelessWidget { + final double width; + + const SignupSection({super.key, required this.width}); + + @override + Widget build(BuildContext context) { + return Column( + key: const Key('signup_section_column'), + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + key: const Key('signup_section_container'), + width: width, + height: 1, + color: const Color(0xffA2A2A2), + ), + const SizedBox(height: 5), + Row( + key: const Key('signup_section'), + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Don't have an account? ", + key: const Key('signup_section_text'), + style: TextStyle(fontSize: width * .040), + ), + TextButton( + key: const Key('signup_section_button'), + child: Text( + 'Sign up', + style: TextStyle( + color: const Color(0xff00258B), + fontSize: width * .040, + fontWeight: FontWeight.bold, + ), + ), + onPressed: () => debugPrint('Sign Up'), + ), + ], + ), + ], + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/login/components/username_textbox.dart b/clone-instagram-login-Refactoring/lib/app/modules/login/components/username_textbox.dart new file mode 100644 index 0000000..6274589 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/login/components/username_textbox.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; + +class UsernameTextbox extends StatelessWidget { + const UsernameTextbox({ + super.key, + required this.width, + required this.checkInputNotNull, + required this.usernameController, + }); + + final double width; + final TextEditingController usernameController; + final VoidCallback checkInputNotNull; + + @override + Widget build(BuildContext context) { + return Container( + key: const Key('username_textbox_container'), + width: width * .90, + height: width * .14, + decoration: const BoxDecoration( + color: Color(0xffE8E8E8), + borderRadius: BorderRadius.all( + Radius.circular(5), + ), + ), + child: Padding( + key: const Key('username_textbox_padding'), + padding: const EdgeInsets.symmetric(horizontal: 15), + child: Center( + key: const Key('username_textbox_center'), + child: TextField( + key: const Key('username_textfield'), + onChanged: (text) { + checkInputNotNull(); + }, + controller: usernameController, + style: const TextStyle( + fontSize: 15, + ), + decoration: const InputDecoration.collapsed( + hintText: 'Phone number , email or username', + ), + ), + ), + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/login/login_page.dart b/clone-instagram-login-Refactoring/lib/app/modules/login/login_page.dart new file mode 100644 index 0000000..22457f8 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/login/login_page.dart @@ -0,0 +1,133 @@ +import 'components/facebook_login.dart'; +import 'components/forgot_access.dart'; +import 'components/or_divider.dart'; +import 'components/signup_section.dart'; +import 'components/login_button.dart'; +import 'components/password_textbox.dart'; +import 'package:flutter/material.dart'; + +import 'components/language_dropdown.dart'; +import 'components/username_textbox.dart'; + +class LoginPage extends StatefulWidget { + const LoginPage({super.key}); + + @override + LoginPageState createState() => LoginPageState(); +} + +class LoginPageState extends State { + TextEditingController usernameController = TextEditingController(); + TextEditingController passwordController = TextEditingController(); + + bool inputTextNotNull = false; + + void checkInputNotNull() { + setState(() { + if (usernameController.text.length >= 2 && + passwordController.text.length >= 2) { + inputTextNotNull = true; + } else { + inputTextNotNull = false; + } + }); + } + + void openHomePage() { + inputTextNotNull ? Navigator.pushNamed(context, '/home') : null; + } + + @override + Widget build(BuildContext context) { + final width = MediaQuery.of(context).size.width; + final height = MediaQuery.of(context).size.height; + + double getAvailableHeight() { + return height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom; + } + + return Scaffold( + key: const Key('login_page_scaffold'), + body: SafeArea( + key: const Key('login_page_safe_area'), + child: SingleChildScrollView( + key: const Key('login_page_scroll_view'), + child: ConstrainedBox( + key: const Key('login_page_constrained_box'), + constraints: BoxConstraints(minHeight: getAvailableHeight()), + child: Column( + key: const Key('login_page_column'), + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + key: const Key('login_page_language_dropdown_container'), + width: width, + alignment: Alignment.topCenter, + child: const LanguageDropdown(), + ), + Column( + key: const Key('login_page_content_column'), + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + key: const Key('login_page_instagram_logo'), + 'assets/instagram_logo.png', + width: width * .5, + ), + const SizedBox(height: 15), + UsernameTextbox( + key: const Key('login_page_username_textbox'), + width: width, + checkInputNotNull: checkInputNotNull, + usernameController: usernameController, + ), + const SizedBox(height: 10), + PasswordTextbox( + key: const Key('login_page_password_textbox'), + width: width, + checkInputNotNull: checkInputNotNull, + passwordController: passwordController), + const SizedBox(height: 10), + LoginButton( + key: const Key('login_page_login_button'), + width: width, + inputTextNotNull: inputTextNotNull, + onPressed: () { + openHomePage(); + }, + ), + const SizedBox( + height: 15, + ), + ForgotAccess( + key: const Key('login_page_forgot_access'), + width: width, + ), + const SizedBox(height: 15), + ORDivider( + key: const Key('login_page_or_divider'), + width: width, + ), + const SizedBox( + height: 20, + ), + FacebookLogin( + key: const Key('login_page_facebook_login'), + width: width, + ), + ], + ), + SignupSection( + key: const Key('login_page_signup_section'), + width: width, + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/post/post_page.dart b/clone-instagram-login-Refactoring/lib/app/modules/post/post_page.dart new file mode 100644 index 0000000..57232eb --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/post/post_page.dart @@ -0,0 +1,76 @@ +import 'package:example_widget_testing/app/widgets/bottom_navbar.dart'; +import 'package:example_widget_testing/app/widgets/post_item.dart'; +import 'package:example_widget_testing/core/values/constant/post_json.dart'; +import 'package:example_widget_testing/core/values/constant/story_json.dart'; +import 'package:flutter/material.dart'; + +import '../../data/models/post.dart'; + +class PostPage extends StatefulWidget { + final List posts; + const PostPage({super.key, required this.posts}); + + @override + PostPageState createState() => PostPageState(); +} + +class PostPageState extends State { + final List listPost = posts.map((e) => Post.fromJson(e)).toList(); + void updatePostLike(id) { + setState(() { + for (var element in listPost) { + if (element.id == id) { + element.isLoved = !element.isLoved!; + } + } + }); + } + + @override + void initState() { + super.initState(); + posts = widget.posts; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: const Key('post_page_scaffold'), + backgroundColor: Colors.black, + appBar: AppBar( + backgroundColor: Colors.black, + title: const Text("Post"), + ), + body: SingleChildScrollView( + key: const Key('post_page_single_child_scroll_view'), + child: Column( + key: const Key('post_page_column'), + children: [ + Column( + key: const Key('post_page_column'), + children: listPost.map((post) { + return PostItem( + key: Key('post_item_${post.id}'), // add key for testing + postImg: post.postImg!, + profileImg: post.profileImg!, + name: post.name!, + caption: post.caption!, + isLoved: post.isLoved!, + viewCount: post.commentCount!, + likedBy: post.likedBy!, + dayAgo: post.timeAgo!, + userPhoto: profile, + onPressed: () => updatePostLike(post.id!), + ); + }).toList(), + ) + ], + ), + ), + bottomNavigationBar: const BottomNavbar( + key: Key('post_page_bottom_navbar'), + pageIndex: 4, + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/search/components/search_category_item.dart b/clone-instagram-login-Refactoring/lib/app/modules/search/components/search_category_item.dart new file mode 100644 index 0000000..c867bfc --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/search/components/search_category_item.dart @@ -0,0 +1,30 @@ +// import 'package:example_widget_testing/core/theme/colors.dart'; +// import 'package:flutter/material.dart'; + +// class CategoryStoryItem extends StatelessWidget { +// final String name; + +// const CategoryStoryItem({super.key, required this.name}); + +// @override +// Widget build(BuildContext context) { +// return Padding( +// padding: const EdgeInsets.only(right: 10), +// child: Container( +// decoration: BoxDecoration( +// borderRadius: BorderRadius.circular(10), +// color: black, +// border: Border.all(color: white.withOpacity(0.2))), +// child: Padding( +// padding: +// const EdgeInsets.only(left: 20, right: 25, top: 10, bottom: 10), +// child: Text( +// name, +// style: const TextStyle( +// color: white, fontWeight: FontWeight.w500, fontSize: 15), +// ), +// ), +// ), +// ); +// } +// } diff --git a/clone-instagram-login-Refactoring/lib/app/modules/search/search_list_page.dart b/clone-instagram-login-Refactoring/lib/app/modules/search/search_list_page.dart new file mode 100644 index 0000000..73012fd --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/search/search_list_page.dart @@ -0,0 +1,43 @@ +// import 'package:example_widget_testing/core/theme/colors.dart'; +// import 'package:flutter/material.dart'; + +// class SearchListPage extends StatefulWidget { +// const SearchListPage({super.key}); + +// @override +// SearchListPageState createState() => SearchListPageState(); +// } + +// class SearchListPageState extends State { +// @override +// Widget build(BuildContext context) { +// return getBody(); +// } + +// Widget getBody() { +// var size = MediaQuery.of(context).size; +// return ListView( +// children: [ +// Container( +// margin: const EdgeInsets.only(bottom: 15, left: 15, right: 15), +// width: size.width - 30, +// height: 45, +// decoration: BoxDecoration( +// borderRadius: BorderRadius.circular(10), +// color: textFieldBackground), +// child: TextField( +// decoration: InputDecoration( +// border: InputBorder.none, +// prefixIcon: Icon( +// Icons.search, +// color: white.withOpacity(0.3), +// ), +// ), +// style: TextStyle(color: white.withOpacity(0.3)), +// cursorColor: white.withOpacity(0.3), +// ), +// ), +// ], +// ); +// } +// } diff --git a/clone-instagram-login-Refactoring/lib/app/modules/search/search_page.dart b/clone-instagram-login-Refactoring/lib/app/modules/search/search_page.dart new file mode 100644 index 0000000..51a1149 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/search/search_page.dart @@ -0,0 +1,73 @@ +import 'package:example_widget_testing/app/widgets/bottom_navbar.dart'; +import 'package:example_widget_testing/core/theme/colors.dart'; +// import 'package:example_widget_testing/core/values/constant/search_json.dart'; +import 'package:flutter/material.dart'; + +import '../../widgets/post_thumbnail.dart'; + +class SearchPage extends StatefulWidget { + const SearchPage({super.key, required this.searchPosts}); + final List searchPosts; + + @override + SearchPageState createState() => SearchPageState(); +} + +class SearchPageState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + key: const Key('search_page_scaffold'), + backgroundColor: Colors.black, + appBar: const PreferredSize( + key: Key('search_page_app_bar_preferred_size'), + preferredSize: Size.fromHeight(0), + child: SizedBox( + height: 20, + ), + ), + body: ListView( + key: const Key('search_page_listview'), + children: [ + Container( + key: const Key('search_page_textfield_container'), + margin: const EdgeInsets.only(bottom: 15, left: 15, right: 15), + height: 45, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: textFieldBackground), + child: TextField( + key: const Key('search_page_textfield'), + onTap: () { + debugPrint('clicked'); + }, + decoration: InputDecoration( + border: InputBorder.none, + prefixIcon: Icon( + Icons.search, + color: white.withOpacity(0.3), + ), + ), + style: TextStyle(color: white.withOpacity(0.3)), + cursorColor: white.withOpacity(0.3), + ), + ), + Wrap( + key: const Key('search_page_wrap'), + spacing: 1, + runSpacing: 1, + children: widget.searchPosts.map((imageUrl) { + return PostThumbnail( + imageUrl: imageUrl, + ); + }).toList(), + ) + ], + ), + bottomNavigationBar: const BottomNavbar( + key: Key('search_page_bottom_navbar'), + pageIndex: 1, + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/modules/upload/upload_page.dart b/clone-instagram-login-Refactoring/lib/app/modules/upload/upload_page.dart new file mode 100644 index 0000000..1f40e79 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/modules/upload/upload_page.dart @@ -0,0 +1,40 @@ +import 'package:example_widget_testing/app/widgets/bottom_navbar.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; + +class UploadPage extends StatelessWidget { + const UploadPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.black, + appBar: AppBar( + key: const Key("upload_page_appbar"), + backgroundColor: Colors.black, + title: const Text("Upload"), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgPicture.asset( + "assets/images/upload_icon.svg", + width: 60, + ), + const SizedBox(height: 20.0), + const Text( + "Upload Page", + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + ], + ), + ), + bottomNavigationBar: const BottomNavbar(pageIndex: 2), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/widgets/bottom_navbar.dart b/clone-instagram-login-Refactoring/lib/app/widgets/bottom_navbar.dart new file mode 100644 index 0000000..e80c884 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/widgets/bottom_navbar.dart @@ -0,0 +1,41 @@ +import 'package:example_widget_testing/core/values/constant/navbarmenu_json.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; + +class BottomNavbar extends StatelessWidget { + final int pageIndex; + const BottomNavbar({super.key, required this.pageIndex}); + + @override + Widget build(BuildContext context) { + void navigateToPage(int index) { + Navigator.pushNamed(context, navbarMenuList[index].path!); + } + + return Container( + key: const Key("bottom_navigation_bar_container"), + width: double.infinity, + height: 55, + color: Colors.black, + padding: const EdgeInsets.only(left: 20, right: 20, bottom: 20, top: 15), + child: Row( + key: const Key("bottom_navigation_bar_row"), + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: List.generate(navbarMenuList.length, (index) { + return InkWell( + key: Key("bottom_item_$index"), + onTap: () { + navigateToPage(index); + }, + child: SvgPicture.asset( + pageIndex == index + ? navbarMenuList[index].activeIcon! + : navbarMenuList[index].inactiveIcon!, + width: 27, + ), + ); + }), + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/widgets/post_item.dart b/clone-instagram-login-Refactoring/lib/app/widgets/post_item.dart new file mode 100644 index 0000000..7dfafcc --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/widgets/post_item.dart @@ -0,0 +1,303 @@ +import 'package:example_widget_testing/core/theme/colors.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +// import 'package:line_icons/line_icons.dart'; + +class PostItem extends StatelessWidget { + final String profileImg; + final String name; + final String postImg; + final String caption; + final bool isLoved; + final String likedBy; + final String viewCount; + final String dayAgo; + final String userPhoto; + final VoidCallback onPressed; + + const PostItem({ + super.key, + required this.profileImg, + required this.name, + required this.postImg, + required this.caption, + required this.isLoved, + required this.likedBy, + required this.viewCount, + required this.dayAgo, + required this.userPhoto, + required this.onPressed, + }); + + @override + Widget build(BuildContext context) { + return Padding( + key: const Key('post_item_padding'), + padding: const EdgeInsets.only(bottom: 10), + child: Column( + key: const Key('post_item_column'), + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + key: const Key('post_item_user_info_container'), + padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15), + margin: const EdgeInsets.only(bottom: 12), + child: Row( + key: const Key('post_item_user_info_row'), + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + key: const Key('post_item_user_profile_img_container'), + width: 40, + height: 40, + margin: const EdgeInsets.only(right: 15), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: NetworkImage(profileImg), + fit: BoxFit.cover, + ), + ), + ), + Expanded( + key: const Key('post_item_user_name_expanded'), + child: Text( + key: const Key('post_item_user_name_text'), + name, + style: const TextStyle( + color: white, + fontSize: 15, + fontWeight: FontWeight.w500, + ), + ), + ), + const Icon( + key: Key('post_item_user_more_icon'), + Icons.more_horiz, + color: white, + ) + ], + ), + ), + Stack( + children: [ + Material( + child: InkWell( + onDoubleTap: () => onPressed(), + child: Container( + key: const Key('post_item_image_container'), + height: 400, + margin: const EdgeInsets.only(bottom: 10), + decoration: BoxDecoration( + image: DecorationImage( + image: NetworkImage(postImg), + fit: BoxFit.cover, + ), + ), + ), + ), + ), + // put love icon here + Positioned( + key: const Key('post_item_love_icon_positioned'), + bottom: 20, + right: 20, + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: onPressed, + child: SvgPicture.asset( + key: const Key('post_item_love_icon'), + isLoved + ? "assets/images/loved_icon.svg" + : "assets/images/love_icon.svg", + width: 27, + ), + ), + ), + ), + ], + ), + Container( + key: const Key('post_item_actions_container'), + padding: const EdgeInsets.fromLTRB(15, 3, 15, 0), + margin: const EdgeInsets.only(bottom: 12), + child: Row( + key: const Key('post_item_actions_row'), + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + key: const Key('post_item_actions_left_row'), + children: [ + Material( + color: Colors.transparent, + child: InkWell( + onTap: onPressed, + child: SvgPicture.asset( + key: const Key('post_item_actions_love_icon'), + isLoved + ? "assets/images/loved_icon.svg" + : "assets/images/love_icon.svg", + width: 27, + ), + ), + ), + const SizedBox( + key: Key('post_item_actions_left_row_sized_box_1'), + width: 20), + SvgPicture.asset( + "assets/images/comment_icon.svg", + key: const Key('post_item_actions_comment_icon'), + width: 27, + ), + const SizedBox( + key: Key('post_item_actions_left_row_sized_box_2'), + width: 20), + SvgPicture.asset( + "assets/images/message_icon.svg", + key: const Key('post_item_actions_message_icon'), + width: 27, + ), + ], + ), + SvgPicture.asset( + "assets/images/save_icon.svg", + key: const Key('post_item_actions_save_icon'), + width: 27, + ), + ], + ), + ), + Container( + key: const Key('post_item_likes_container'), + padding: const EdgeInsets.symmetric(horizontal: 15), + margin: const EdgeInsets.only(bottom: 12), + child: RichText( + key: const Key('post_item_likes_rich_text'), + text: TextSpan( + children: [ + TextSpan( + text: "Liked by $likedBy and Other", + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + ), + Container( + key: const Key('post_item_caption_container'), + padding: const EdgeInsets.symmetric(horizontal: 15), + margin: const EdgeInsets.only(bottom: 12), + child: RichText( + key: const Key('post_item_caption_rich_text'), + text: TextSpan( + children: [ + TextSpan( + text: "$name ", + style: const TextStyle( + fontSize: 15, fontWeight: FontWeight.w700), + ), + TextSpan( + text: caption, + style: const TextStyle( + fontSize: 15, fontWeight: FontWeight.w500), + ), + ], + ), + ), + ), + Container( + key: const Key('post_item_view_comments_container'), + padding: const EdgeInsets.symmetric(horizontal: 15), + margin: const EdgeInsets.only(bottom: 12), + child: Text( + key: const Key('post_item_view_comments_text'), + "View $viewCount comments", + style: TextStyle( + color: white.withOpacity(0.5), + fontSize: 15, + fontWeight: FontWeight.w500), + ), + ), + Container( + key: const Key('post_item_add_comment_container'), + padding: const EdgeInsets.symmetric(horizontal: 15), + margin: const EdgeInsets.only(bottom: 12), + child: Row( + key: const Key('post_item_add_comment_row'), + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + key: const Key('post_item_add_comment_left_row'), + children: [ + Container( + key: const Key('post_item_add_comment_avatar_container'), + width: 30, + height: 30, + margin: const EdgeInsets.only(right: 15), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: NetworkImage(userPhoto), + fit: BoxFit.cover, + ), + ), + ), + Text( + key: const Key('post_item_add_comment_text'), + "Add a comment...", + style: TextStyle( + color: white.withOpacity(0.5), + fontSize: 15, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + Row( + key: const Key('post_item_add_comment_right_row'), + children: [ + const Text( + key: Key('post_item_add_laugh_emoji_text'), + "😂", + style: TextStyle(fontSize: 20), + ), + const SizedBox(width: 10), + const Text( + key: Key('post_item_add_love_emoji_text'), + "😍", + style: TextStyle(fontSize: 20), + ), + const SizedBox(width: 10), + Icon( + key: const Key('post_item_add_circle_icon'), + Icons.add_circle, + color: white.withOpacity(0.5), + size: 18, + ) + ], + ) + ], + ), + ), + Padding( + key: const Key('post_item_day_ago_padding'), + padding: const EdgeInsets.symmetric(horizontal: 15), + child: Text( + key: const Key('post_item_day_ago_text'), + dayAgo, + style: TextStyle( + color: white.withOpacity(0.5), + fontSize: 15, + fontWeight: FontWeight.w500, + ), + ), + ) + ], + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/widgets/post_thumbnail.dart b/clone-instagram-login-Refactoring/lib/app/widgets/post_thumbnail.dart new file mode 100644 index 0000000..1808aa8 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/widgets/post_thumbnail.dart @@ -0,0 +1,23 @@ +import 'package:flutter/widgets.dart'; + +class PostThumbnail extends StatelessWidget { + final String imageUrl; + + const PostThumbnail({super.key, required this.imageUrl}); + + @override + Widget build(BuildContext context) { + final size = MediaQuery.of(context).size; + return Container( + key: Key(imageUrl), + width: (size.width - 3) / 3, + height: (size.width - 3) / 3, + decoration: BoxDecoration( + image: DecorationImage( + image: NetworkImage(imageUrl), + fit: BoxFit.cover, + ), + ), + ); + } +} diff --git a/clone-instagram-login-Refactoring/lib/app/widgets/root_app.dart b/clone-instagram-login-Refactoring/lib/app/widgets/root_app.dart new file mode 100644 index 0000000..b892978 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/app/widgets/root_app.dart @@ -0,0 +1,20 @@ +// import 'package:example_widget_testing/core/values/constant/navbarmenu_json.dart'; +// import 'package:flutter/material.dart'; +// import 'package:flutter_svg/svg.dart'; + +// class BottomNavbar extends StatelessWidget { +// final int pageIndex; +// const BottomNavbar({ +// super.key, +// required this.pageIndex, +// }); + +// @override +// Widget build(BuildContext context) { +// void navigateToPage(int index) { +// Navigator.pushNamed(context, navbarMenuList[index].path!); +// } + +// throw UnimplementedError(); +// } +// } diff --git a/clone-instagram-login-Refactoring/lib/core/theme/colors.dart b/clone-instagram-login-Refactoring/lib/core/theme/colors.dart new file mode 100644 index 0000000..898ce74 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/core/theme/colors.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +const appBarColor = Color(0xFF131313); +const appFooterColor = Color(0xFF131313); +const primary = Color(0xFF000000); +const white = Color(0xFFFFFFFF); +const black = Color(0xFF000000); +const textFieldBackground = Color(0xFF262626); +const buttonFollowColor = Color(0xFF0494F5); +const storyBorderColor = [Color(0xFF9B2282), Color(0xFFEEA863)]; diff --git a/clone-instagram-login-Refactoring/lib/core/values/constant/navbarmenu_json.dart b/clone-instagram-login-Refactoring/lib/core/values/constant/navbarmenu_json.dart new file mode 100644 index 0000000..4544952 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/core/values/constant/navbarmenu_json.dart @@ -0,0 +1,42 @@ +import '../../../app/data/models/navbar_menu.dart'; + +List navbarmenu = [ + { + "id": 1, + "name": "Home", + "active_icon": "assets/images/home_active_icon.svg", + "inactive_icon": "assets/images/home_icon.svg", + "path": "/home", + }, + { + "id": 2, + "name": "Search", + "active_icon": "assets/images/search_active_icon.svg", + "inactive_icon": "assets/images/search_icon.svg", + "path": "/search" + }, + { + "id": 3, + "name": "Upload", + "active_icon": "assets/images/upload_active_icon.svg", + "inactive_icon": "assets/images/upload_icon.svg", + "path": "/upload" + }, + { + "id": 4, + "name": "Activity", + "active_icon": "assets/images/love_active_icon.svg", + "inactive_icon": "assets/images/love_icon.svg", + "path": "/activity" + }, + { + "id": 5, + "name": "Account", + "active_icon": "assets/images/account_active_icon.svg", + "inactive_icon": "assets/images/account_icon.svg", + "path": "/account" + } +]; + +List navbarMenuList = + navbarmenu.map((e) => NavbarMenu.fromJson(e)).toList(); diff --git a/clone-instagram-login-Refactoring/lib/core/values/constant/post_json.dart b/clone-instagram-login-Refactoring/lib/core/values/constant/post_json.dart new file mode 100644 index 0000000..6a10e35 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/core/values/constant/post_json.dart @@ -0,0 +1,68 @@ +List posts = [ + { + "id": 1, + "name": "Kal El", + "profileImg": + "https://images.unsplash.com/photo-1634861949375-3fc4bd412f2f?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80", + "postImg": + "https://images.unsplash.com/photo-1634861949375-3fc4bd412f2f?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80", + "caption": " Nice cape, Clark.", + "isLoved": true, + "commentCount": "10", + "likedBy": "whereavygoes", + "timeAgo": "1 day ago" + }, + { + "id": 2, + "name": "Martian", + "profileImg": + "https://images.unsplash.com/photo-1614935981447-893ce3858657?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=735&q=80", + "postImg": + "https://images.unsplash.com/photo-1614935981447-893ce3858657?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=735&q=80", + "caption": + " Home is where the heart is. And my heart is in the middle of nowhere.", + "isLoved": true, + "commentCount": "10", + "likedBy": "sonitakhoun", + "timeAgo": "1 day ago" + }, + { + "id": 3, + "name": "Arthur Curry", + "profileImg": + "https://images.unsplash.com/photo-1584102534935-a63e84096e83?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1469&q=80", + "postImg": + "https://images.unsplash.com/photo-1584102534935-a63e84096e83?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1469&q=80", + "caption": " G'day, mate.", + "isLoved": false, + "commentCount": "60", + "likedBy": "Amber Heard", + "timeAgo": "3 day ago" + }, + { + "id": 4, + "name": "Victor Stone", + "profileImg": + "https://images.unsplash.com/photo-1616142914433-71120bc70202?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1528&q=80", + "postImg": + "https://images.unsplash.com/photo-1616142914433-71120bc70202?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1528&q=80", + "caption": "It's all encoded", + "isLoved": false, + "commentCount": "70", + "likedBy": "sonitakhoun", + "timeAgo": "3 day ago" + }, + { + "id": 5, + "name": "Bruce Wayne", + "profileImg": + "https://images.unsplash.com/photo-1497124401559-3e75ec2ed794?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80", + "postImg": + "https://images.unsplash.com/photo-1497124401559-3e75ec2ed794?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80", + "caption": "I'm Batman", + "isLoved": false, + "commentCount": "70", + "likedBy": "sonitakhoun", + "timeAgo": "3 day ago" + } +]; diff --git a/clone-instagram-login-Refactoring/lib/core/values/constant/profile_json.dart b/clone-instagram-login-Refactoring/lib/core/values/constant/profile_json.dart new file mode 100644 index 0000000..aa1666e --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/core/values/constant/profile_json.dart @@ -0,0 +1,14 @@ +final profileJson = { + "username": "iclop", + "name": "IClop Student", + "bio": "Apperentice", + "profilePic": + "https://images.unsplash.com/photo-1614935981447-893ce3858657?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=735&q=80", + "profileBackground": "assets/images/profile_background.jpg", + "profileBackgroundBlur": "assets/images/profile_background_blur.jpg", + "stats": [ + {"count": 0, "label": "Posts"}, + {"count": 0, "label": "Followers"}, + {"count": 0, "label": "Following"} + ] +}; diff --git a/clone-instagram-login-Refactoring/lib/core/values/constant/profile_tabs_json.dart b/clone-instagram-login-Refactoring/lib/core/values/constant/profile_tabs_json.dart new file mode 100644 index 0000000..9d0680f --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/core/values/constant/profile_tabs_json.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; + +final List tabs = [ + { + "id": 0, + "title": "posts", + "icon": Icons.grid_on_outlined, + }, + { + "id": 1, + "title": "tags", + "icon": Icons.person_pin_outlined, + } +]; diff --git a/clone-instagram-login-Refactoring/lib/core/values/constant/search_json.dart b/clone-instagram-login-Refactoring/lib/core/values/constant/search_json.dart new file mode 100644 index 0000000..0bc5ba4 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/core/values/constant/search_json.dart @@ -0,0 +1,28 @@ +List searchCategories = [ + "Shop", + "Decor", + "Travel", + "Architechture", + "Food", + "Art", + "Style", + "TV & Movies", + "Music", + "DIY", + "Comics" +]; + +List searchImages = [ + "https://images.unsplash.com/photo-1504123010103-b1f3fe484a32?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80", + "https://images.unsplash.com/photo-1497316730643-415fac54a2af?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80", + "https://images.unsplash.com/photo-1576092762793-c0e9395ec4b9?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80", + "https://images.unsplash.com/photo-1597182322624-232ca7819eaa?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=688&q=80", + "https://images.unsplash.com/photo-1581091007718-0c50d599bfd0?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80", + "https://images.unsplash.com/photo-1503428593586-e225b39bddfe?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80", + "https://images.unsplash.com/photo-1497124401559-3e75ec2ed794?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80", + "https://images.unsplash.com/photo-1616142914433-71120bc70202?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1528&q=80", + "https://images.unsplash.com/photo-1584102534935-a63e84096e83?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1469&q=80", + "https://images.unsplash.com/photo-1614935981447-893ce3858657?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=735&q=80", + "https://images.unsplash.com/photo-1634861949375-3fc4bd412f2f?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80", + "https://images.unsplash.com/photo-1506901437675-cde80ff9c746?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60", +]; diff --git a/clone-instagram-login-Refactoring/lib/core/values/constant/story_json.dart b/clone-instagram-login-Refactoring/lib/core/values/constant/story_json.dart new file mode 100644 index 0000000..1450ae5 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/core/values/constant/story_json.dart @@ -0,0 +1,38 @@ +// user prfile +String profile = + "https://images.unsplash.com/photo-1504123010103-b1f3fe484a32?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80"; +String name = "Barry Allen"; + +// stories +List stories = [ + { + "id": 1, + "img": + "https://images.unsplash.com/photo-1503428593586-e225b39bddfe?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80", + "name": "Lois Lane" + }, + { + "id": 2, + "img": + "https://images.unsplash.com/photo-1581091007718-0c50d599bfd0?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80", + "name": "Silas Stone" + }, + { + "id": 3, + "img": + "https://images.unsplash.com/photo-1597182322624-232ca7819eaa?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=688&q=80", + "name": "Mera" + }, + { + "id": 4, + "img": + "https://images.unsplash.com/photo-1576092762793-c0e9395ec4b9?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80", + "name": "Pennyworth" + }, + { + "id": 5, + "img": + "https://images.unsplash.com/photo-1497316730643-415fac54a2af?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80", + "name": "Jimmy Olsen" + } +]; diff --git a/clone-instagram-login-Refactoring/lib/main.dart b/clone-instagram-login-Refactoring/lib/main.dart new file mode 100644 index 0000000..6c30e19 --- /dev/null +++ b/clone-instagram-login-Refactoring/lib/main.dart @@ -0,0 +1,44 @@ +import 'package:example_widget_testing/app/modules/account/account_page.dart'; +import 'package:example_widget_testing/app/modules/activity/activity_page.dart'; +import 'package:example_widget_testing/app/modules/home/home_page.dart'; +import 'package:example_widget_testing/app/modules/login/login_page.dart'; +import 'package:example_widget_testing/app/modules/post/post_page.dart'; +import 'package:example_widget_testing/app/modules/search/search_page.dart'; +import 'package:example_widget_testing/core/values/constant/post_json.dart'; +import 'package:example_widget_testing/core/values/constant/profile_json.dart'; +import 'package:example_widget_testing/core/values/constant/search_json.dart'; +import 'package:flutter/material.dart'; + +import 'app/modules/upload/upload_page.dart'; +import 'core/values/constant/story_json.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + debugShowCheckedModeBanner: false, + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: const LoginPage(), + routes: { + '/login': (context) => const LoginPage(), + '/home': (context) => + HomePage(posts: posts, stories: stories, profileData: profileJson), + '/search': (context) => SearchPage(searchPosts: searchImages), + '/upload': (context) => const UploadPage(), + '/activity': (context) => const ActivityPage(), + '/account': (context) => AccountPage( + profileData: profileJson, posts: posts, stories: stories), + '/post': (context) => PostPage(posts: posts), + }, + ); + } +} diff --git a/clone-instagram-login-Refactoring/linux/.gitignore b/clone-instagram-login-Refactoring/linux/.gitignore new file mode 100644 index 0000000..d3896c9 --- /dev/null +++ b/clone-instagram-login-Refactoring/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/clone-instagram-login-Refactoring/linux/CMakeLists.txt b/clone-instagram-login-Refactoring/linux/CMakeLists.txt new file mode 100644 index 0000000..a81fd7a --- /dev/null +++ b/clone-instagram-login-Refactoring/linux/CMakeLists.txt @@ -0,0 +1,138 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "example_widget_testing") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.example_widget_testing") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/clone-instagram-login-Refactoring/linux/flutter/CMakeLists.txt b/clone-instagram-login-Refactoring/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000..d5bd016 --- /dev/null +++ b/clone-instagram-login-Refactoring/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/clone-instagram-login-Refactoring/linux/flutter/generated_plugin_registrant.cc b/clone-instagram-login-Refactoring/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..e71a16d --- /dev/null +++ b/clone-instagram-login-Refactoring/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/clone-instagram-login-Refactoring/linux/flutter/generated_plugin_registrant.h b/clone-instagram-login-Refactoring/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..e0f0a47 --- /dev/null +++ b/clone-instagram-login-Refactoring/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/clone-instagram-login-Refactoring/linux/flutter/generated_plugins.cmake b/clone-instagram-login-Refactoring/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000..2e1de87 --- /dev/null +++ b/clone-instagram-login-Refactoring/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/clone-instagram-login-Refactoring/linux/main.cc b/clone-instagram-login-Refactoring/linux/main.cc new file mode 100644 index 0000000..e7c5c54 --- /dev/null +++ b/clone-instagram-login-Refactoring/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/clone-instagram-login-Refactoring/linux/my_application.cc b/clone-instagram-login-Refactoring/linux/my_application.cc new file mode 100644 index 0000000..d312ba8 --- /dev/null +++ b/clone-instagram-login-Refactoring/linux/my_application.cc @@ -0,0 +1,104 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "example_widget_testing"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "example_widget_testing"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/clone-instagram-login-Refactoring/linux/my_application.h b/clone-instagram-login-Refactoring/linux/my_application.h new file mode 100644 index 0000000..72271d5 --- /dev/null +++ b/clone-instagram-login-Refactoring/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/clone-instagram-login-Refactoring/macos/.gitignore b/clone-instagram-login-Refactoring/macos/.gitignore new file mode 100644 index 0000000..746adbb --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/clone-instagram-login-Refactoring/macos/Flutter/Flutter-Debug.xcconfig b/clone-instagram-login-Refactoring/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000..c2efd0b --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/clone-instagram-login-Refactoring/macos/Flutter/Flutter-Release.xcconfig b/clone-instagram-login-Refactoring/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000..c2efd0b --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/clone-instagram-login-Refactoring/macos/Flutter/GeneratedPluginRegistrant.swift b/clone-instagram-login-Refactoring/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000..cccf817 --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,10 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { +} diff --git a/clone-instagram-login-Refactoring/macos/Runner.xcodeproj/project.pbxproj b/clone-instagram-login-Refactoring/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..a35d500 --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,572 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* example_widget_testing.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "example_widget_testing.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* example_widget_testing.app */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* example_widget_testing.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/clone-instagram-login-Refactoring/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/clone-instagram-login-Refactoring/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/clone-instagram-login-Refactoring/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/clone-instagram-login-Refactoring/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..d6d7e7a --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/clone-instagram-login-Refactoring/macos/Runner.xcworkspace/contents.xcworkspacedata b/clone-instagram-login-Refactoring/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/clone-instagram-login-Refactoring/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/clone-instagram-login-Refactoring/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/clone-instagram-login-Refactoring/macos/Runner/AppDelegate.swift b/clone-instagram-login-Refactoring/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000..d53ef64 --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..a2ec33f --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000..82b6f9d Binary files /dev/null and b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000..13b35eb Binary files /dev/null and b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000..0a3f5fa Binary files /dev/null and b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 0000000..bdb5722 Binary files /dev/null and b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 0000000..f083318 Binary files /dev/null and b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 0000000..326c0e7 Binary files /dev/null and b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000..2f1632c Binary files /dev/null and b/clone-instagram-login-Refactoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/clone-instagram-login-Refactoring/macos/Runner/Base.lproj/MainMenu.xib b/clone-instagram-login-Refactoring/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 0000000..80e867a --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/clone-instagram-login-Refactoring/macos/Runner/Configs/AppInfo.xcconfig b/clone-instagram-login-Refactoring/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000..3fb7d2f --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = example_widget_testing + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.exampleWidgetTesting + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. diff --git a/clone-instagram-login-Refactoring/macos/Runner/Configs/Debug.xcconfig b/clone-instagram-login-Refactoring/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000..36b0fd9 --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/clone-instagram-login-Refactoring/macos/Runner/Configs/Release.xcconfig b/clone-instagram-login-Refactoring/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000..dff4f49 --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/clone-instagram-login-Refactoring/macos/Runner/Configs/Warnings.xcconfig b/clone-instagram-login-Refactoring/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000..42bcbf4 --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/clone-instagram-login-Refactoring/macos/Runner/DebugProfile.entitlements b/clone-instagram-login-Refactoring/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000..dddb8a3 --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/clone-instagram-login-Refactoring/macos/Runner/Info.plist b/clone-instagram-login-Refactoring/macos/Runner/Info.plist new file mode 100644 index 0000000..4789daa --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/clone-instagram-login-Refactoring/macos/Runner/MainFlutterWindow.swift b/clone-instagram-login-Refactoring/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000..2722837 --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController.init() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/clone-instagram-login-Refactoring/macos/Runner/Release.entitlements b/clone-instagram-login-Refactoring/macos/Runner/Release.entitlements new file mode 100644 index 0000000..852fa1a --- /dev/null +++ b/clone-instagram-login-Refactoring/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/clone-instagram-login-Refactoring/pubspec.lock b/clone-instagram-login-Refactoring/pubspec.lock new file mode 100644 index 0000000..e34e65e --- /dev/null +++ b/clone-instagram-login-Refactoring/pubspec.lock @@ -0,0 +1,476 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "3444216bfd127af50bbe4862d8843ed44db946dd933554f0d7285e89f10e28ac" + url: "https://pub.dev" + source: hosted + version: "50.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "68796c31f510c8455a06fed75fc97d8e5ad04d324a830322ab3efc9feb6201c1" + url: "https://pub.dev" + source: hosted + version: "5.2.0" + archive: + dependency: transitive + description: + name: archive + sha256: "80e5141fafcb3361653ce308776cfd7d45e6e9fbb429e14eec571382c0c5fecb" + url: "https://pub.dev" + source: hosted + version: "3.3.2" + args: + dependency: transitive + description: + name: args + sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + async: + dependency: transitive + description: + name: async + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" + source: hosted + version: "2.10.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777" + url: "https://pub.dev" + source: hosted + version: "2.3.1" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: "31b7c748fd4b9adf8d25d72a4c4a59ef119f12876cf414f94f8af5131d5fa2b0" + url: "https://pub.dev" + source: hosted + version: "8.4.4" + characters: + dependency: transitive + description: + name: characters + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" + source: hosted + version: "1.2.1" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe" + url: "https://pub.dev" + source: hosted + version: "4.4.0" + collection: + dependency: transitive + description: + name: collection + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" + source: hosted + version: "1.17.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + url: "https://pub.dev" + source: hosted + version: "3.0.2" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" + source: hosted + version: "1.0.5" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "5be16bf1707658e4c03078d4a9b90208ded217fb02c163e207d334082412f2fb" + url: "https://pub.dev" + source: hosted + version: "2.2.5" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "04be3e934c52e082558cc9ee21f42f5c1cd7a1262f4c63cd0357c08d5bba81ec" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_driver: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" + source: hosted + version: "2.0.1" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "6ff9fa12892ae074092de2fa6a9938fb21dbabfdaa2ff57dc697ff912fc8d4b2" + url: "https://pub.dev" + source: hosted + version: "1.1.6" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + integration_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + js: + dependency: transitive + description: + name: js + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" + source: hosted + version: "0.6.5" + lints: + dependency: transitive + description: + name: lints + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + logging: + dependency: transitive + description: + name: logging + sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" + source: hosted + version: "0.12.13" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + meta: + dependency: transitive + description: + name: meta + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" + source: hosted + version: "1.8.0" + mockito: + dependency: transitive + description: + name: mockito + sha256: "2a8a17b82b1bde04d514e75d90d634a0ac23f6cb4991f6098009dd56836aeafe" + url: "https://pub.dev" + source: hosted + version: "5.3.2" + network_image_mock: + dependency: "direct dev" + description: + name: network_image_mock + sha256: "855cdd01d42440e0cffee0d6c2370909fc31b3bcba308a59829f24f64be42db7" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" + source: hosted + version: "1.8.2" + path_drawing: + dependency: transitive + description: + name: path_drawing + sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977 + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" + url: "https://pub.dev" + source: hosted + version: "5.1.0" + platform: + dependency: transitive + description: + name: platform + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + process: + dependency: transitive + description: + name: process + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" + source: hosted + version: "4.2.4" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: c2bea18c95cfa0276a366270afaa2850b09b4a76db95d546f3d003dcc7011298 + url: "https://pub.dev" + source: hosted + version: "1.2.7" + source_span: + dependency: transitive + description: + name: source_span + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" + source: hosted + version: "1.9.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + sync_http: + dependency: transitive + description: + name: sync_http + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" + source: hosted + version: "0.4.16" + test_cov_console: + dependency: "direct dev" + description: + name: test_cov_console + sha256: "73519e8be3689d73f5cffb652c12c310acacf48379396d834da937094836e65e" + url: "https://pub.dev" + source: hosted + version: "0.2.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: e7fb6c2282f7631712b69c19d1bff82f3767eea33a2321c14fa59ad67ea391c7 + url: "https://pub.dev" + source: hosted + version: "9.4.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + webdriver: + dependency: transitive + description: + name: webdriver + sha256: ef67178f0cc7e32c1494645b11639dd1335f1d18814aa8435113a92e9ef9d841 + url: "https://pub.dev" + source: hosted + version: "3.0.1" + xml: + dependency: transitive + description: + name: xml + sha256: ac0e3f4bf00ba2708c33fbabbbe766300e509f8c82dbd4ab6525039813f7e2fb + url: "https://pub.dev" + source: hosted + version: "6.1.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + url: "https://pub.dev" + source: hosted + version: "3.1.1" +sdks: + dart: ">=2.18.6 <3.0.0" + flutter: ">=2.11.0-0.1.pre" diff --git a/clone-instagram-login-Refactoring/pubspec.yaml b/clone-instagram-login-Refactoring/pubspec.yaml new file mode 100644 index 0000000..b3637b1 --- /dev/null +++ b/clone-instagram-login-Refactoring/pubspec.yaml @@ -0,0 +1,100 @@ +name: example_widget_testing +description: A new Flutter project. + +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: "none" # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: ">=2.18.6 <3.0.0" + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + flutter_svg: ^1.1.6 + +dev_dependencies: + flutter_test: + sdk: flutter + integration_test: + sdk: flutter + network_image_mock: ^2.0.1 + test_cov_console: ^0.2.2 + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + assets: + - assets/ + - assets/images/ + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + fonts: + - family: Billabong + fonts: + - asset: assets/fonts/Billabong.ttf + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/test.rar b/clone-instagram-login-Refactoring/test.rar similarity index 54% rename from test.rar rename to clone-instagram-login-Refactoring/test.rar index 8f18d11..f6e184d 100644 Binary files a/test.rar and b/clone-instagram-login-Refactoring/test.rar differ diff --git a/clone-instagram-login-Refactoring/test/account_page_test.dart b/clone-instagram-login-Refactoring/test/account_page_test.dart new file mode 100644 index 0000000..c3ce248 --- /dev/null +++ b/clone-instagram-login-Refactoring/test/account_page_test.dart @@ -0,0 +1,2128 @@ +import 'package:example_widget_testing/app/data/models/profile.dart'; +import 'package:example_widget_testing/app/modules/account/account_page.dart'; +import 'package:example_widget_testing/app/modules/account/components/account_name.dart'; +import 'package:example_widget_testing/app/modules/account/components/account_stat.dart'; +import 'package:example_widget_testing/app/modules/account/components/account_tab.dart'; +import 'package:example_widget_testing/app/modules/account/components/grey_button.dart'; +import 'package:example_widget_testing/app/modules/account/components/highlight_item.dart'; +import 'package:example_widget_testing/app/modules/account/components/highlight_list.dart'; +import 'package:example_widget_testing/app/modules/account/components/profile_buttons.dart'; +import 'package:example_widget_testing/app/modules/account/components/profile_information.dart'; +import 'package:example_widget_testing/app/modules/account/components/profile_pic.dart'; +import 'package:example_widget_testing/app/widgets/post_thumbnail.dart'; +import 'package:example_widget_testing/core/values/constant/post_json.dart'; +import 'package:example_widget_testing/core/values/constant/profile_json.dart'; +import 'package:example_widget_testing/core/values/constant/profile_tabs_json.dart'; +import 'package:example_widget_testing/core/values/constant/story_json.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network_image_mock/network_image_mock.dart'; + +import 'helper.dart'; + +bool checkError(int index, dynamic expected, dynamic matcher) { + if (expected == null) { + debugPrint('Account Page Test-$index failed: expected is null'); + return false; + } + try { + expect(expected, matcher); + } catch (e) { + debugPrint('Account Page Test-$index failed:'); + debugPrint(e.toString()); + return false; + } + return true; +} + +final Profile profile = Profile.fromJson(profileJson); + +void main() { + final states = {}; + testWidgets('Check if Account page Appbar is present', + (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: AccountPage( + posts: posts, + stories: stories, + profileData: profileJson, + ), + ), + ), + ); + + final appBarFinder = find.byKey(const Key('app_bar_account')); + checkError(2, appBarFinder, findsOneWidget); + + final appBar = appBarFinder.evaluate().first.widget as AppBar; + checkError(3, appBar.backgroundColor, Colors.black); + checkError(4, appBar.automaticallyImplyLeading, false); + final appBarRowFinder = find.byKey(const Key('app_bar_row')); + if (checkError(5, appBarRowFinder, findsOneWidget)) { + final appBarRow = appBarRowFinder.evaluate().first.widget as Row; + checkError( + 6, appBarRow.mainAxisAlignment, MainAxisAlignment.spaceBetween); + checkError(7, appBarRow.children.length, 2); + + final appBarRowNameFinder = find.byKey(const Key('app_bar_row_name')); + if (checkError( + 8, + find.descendant(of: appBarRowFinder, matching: appBarRowNameFinder), + findsOneWidget, + )) { + final appBarRowName = + appBarRowNameFinder.evaluate().first.widget as Row; + checkError(9, appBarRowName.children.length, 2); + + final appBarRowNameTextFinder = + find.byKey(const Key('app_bar_row_name_text')); + if (checkError( + 10, + find.descendant( + of: appBarRowNameFinder, matching: appBarRowNameTextFinder), + findsOneWidget)) { + final appBarRowNameText = + appBarRowNameTextFinder.evaluate().first.widget as Text; + checkError(11, appBarRowNameText.data, 'iclop'); + checkError(12, appBarRowNameText.style!.fontWeight, FontWeight.bold); + + final appBarRowNameArrowDownIconFinder = + find.byKey(const Key('app_bar_row_name_arrow_down_icon')); + if (checkError( + 13, + find.descendant( + of: appBarRowNameFinder, + matching: appBarRowNameArrowDownIconFinder), + findsOneWidget)) { + final appBarRowNameArrowDownIcon = appBarRowNameArrowDownIconFinder + .evaluate() + .first + .widget as Icon; + checkError( + 14, appBarRowNameArrowDownIcon.icon, Icons.keyboard_arrow_down); + } + } + } + + final appBarRowMenuFinder = find.byKey(const Key('app_bar_row_menu')); + bool appBarRowMenuIsAvailable = checkError( + 15, + find.descendant(of: appBarRowFinder, matching: appBarRowMenuFinder), + findsOneWidget); + if (appBarRowMenuIsAvailable) { + final appBarRowMenu = + appBarRowMenuFinder.evaluate().first.widget as Row; + checkError(16, appBarRowMenu.children.length, 3); + + final appBarRowMenuUploadIconFinder = + find.byKey(const Key('app_bar_row_menu_upload_icon')); + bool appBarRowMenuUploadIconIsAvailable = checkError( + 17, + find.descendant( + of: appBarRowMenuFinder, + matching: appBarRowMenuUploadIconFinder), + findsOneWidget); + bool appBarRowMenuUploadIconIsSvgPicture = checkError( + 18, + appBarRowMenuUploadIconFinder.evaluate().first.widget, + isA()); + if (appBarRowMenuUploadIconIsAvailable && + appBarRowMenuUploadIconIsSvgPicture) { + final appBarRowMenuUploadIcon = appBarRowMenuUploadIconFinder + .evaluate() + .first + .widget as SvgPicture; + checkError(19, appBarRowMenuUploadIcon.width, 27); + bool appBarRowMenuUploadIconIsAssetPicture = checkError( + 20, + appBarRowMenuUploadIcon.pictureProvider.runtimeType, + ExactAssetPicture); + if (appBarRowMenuUploadIconIsAssetPicture) { + final appBarRowMenuUploadIconAssetPicture = + appBarRowMenuUploadIcon.pictureProvider as ExactAssetPicture; + checkError(21, appBarRowMenuUploadIconAssetPicture.assetName, + "assets/images/upload_icon.svg"); + } + } + + final appBarRowMenuHamburgerIconFinder = + find.byKey(const Key('app_bar_row_menu_hamburger_icon')); + bool appBarRowMenuHamburgerIconIsAvailable = checkError( + 22, + find.descendant( + of: appBarRowMenuFinder, + matching: appBarRowMenuHamburgerIconFinder), + findsOneWidget); + bool appBarRowMenuHamburgerIconIsIcon = checkError( + 23, + appBarRowMenuHamburgerIconFinder.evaluate().first.widget, + isA()); + if (appBarRowMenuHamburgerIconIsAvailable && + appBarRowMenuHamburgerIconIsIcon) { + final appBarRowMenuHamburgerIcon = + appBarRowMenuHamburgerIconFinder.evaluate().first.widget as Icon; + checkError(24, appBarRowMenuHamburgerIcon.size, 35); + checkError(25, appBarRowMenuHamburgerIcon.icon, Icons.menu); + } + } + } + }); + testWidgets("Check if Account page body is present", (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: AccountPage( + posts: posts, + stories: stories, + profileData: profileJson, + ), + ), + ), + ); + + final accountPageListViewFinder = find.byKey( + const Key('account_page_listview'), + ); + checkError(26, accountPageListViewFinder, findsOneWidget); + + final accountStatFinder = find.byKey(const Key('account_stat')); + checkError(27, accountStatFinder, findsOneWidget); + + final accountNameFinder = find.byKey(const Key('account_name')); + checkError(28, accountNameFinder, findsOneWidget); + + final profileButtons = find.byKey(const Key('profile_buttons')); + checkError(29, profileButtons, findsOneWidget); + + final highlightList = find.byKey(const Key('highlight_list')); + checkError(30, highlightList, findsOneWidget); + + final accountTab = find.byKey(const Key('account_tab')); + checkError(31, accountTab, findsOneWidget); + + final accountPagePostWrapFinder = + find.byKey(const Key('account_page_post_wrap')); + bool isAccountPagePostWrapAvailable = checkError( + 32, + accountPagePostWrapFinder, + findsOneWidget, + ); + if (isAccountPagePostWrapAvailable) { + final accountPagePostWrap = + accountPagePostWrapFinder.evaluate().first.widget as Wrap; + checkError(33, accountPagePostWrap.spacing, 1.5); + checkError(34, accountPagePostWrap.runSpacing, 1.5); + checkError(35, accountPagePostWrap.children.length, posts.length); + posts.asMap().forEach((key, value) { + final accountPostInkWellFinder = find.byKey( + Key('account_post_inkwell_$key'), + ); + bool isAccountPostInkWellAvailable = checkError( + 351, + accountPostInkWellFinder, + findsOneWidget, + ); + if (isAccountPostInkWellAvailable) { + checkError( + 352, + accountPostInkWellFinder.evaluate().first.widget, + isA(), + ); + final accountPostThumbnailFinder = find.byKey( + Key('account_post_thumbnail_$key'), + ); + bool isAccountPostThumbnailAvailable = checkError( + 353, + accountPostThumbnailFinder, + findsOneWidget, + ); + if (isAccountPostThumbnailAvailable) { + bool accountPostThumbnailIsPostThumbnail = checkError( + 354, + accountPostThumbnailFinder.evaluate().first.widget, + isA(), + ); + if (accountPostThumbnailIsPostThumbnail) { + final accountPostThumbnail = accountPostThumbnailFinder + .evaluate() + .first + .widget as PostThumbnail; + checkError( + 355, + accountPostThumbnail.imageUrl, + posts[key]['postImg'], + ); + } + } + } + }); + } + }); + testWidgets("Check if account stats is present", (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: AccountStat(profile: profile), + ), + ), + ); + + final accountPageProfileRowFinder = + find.byKey(const Key('account_page_profile_row')); + bool accounntPageListViewIsAvailable = checkError( + 26, + accountPageProfileRowFinder, + findsOneWidget, + ); + bool accounntPageListViewIsRow = checkError( + 27, + accountPageProfileRowFinder.evaluate().first.widget, + isA(), + ); + if (accounntPageListViewIsAvailable && accounntPageListViewIsRow) { + final accountPageProfileRow = + accountPageProfileRowFinder.evaluate().first.widget as Row; + checkError(28, accountPageProfileRow.children.length, 2); + + final profilePicFinder = find.byKey(const Key('profile_pic')); + checkError(29, profilePicFinder, findsOneWidget); + + final accountPageProfileInformationExpandedFinder = find.byKey( + const Key('account_page_profile_information_expanded'), + ); + bool accountPageProfileInformationExpandedIsAvailable = checkError( + 30, + accountPageProfileInformationExpandedFinder, + findsOneWidget, + ); + + checkError( + 31, + accountPageProfileInformationExpandedFinder.evaluate().first.widget, + isA(), + ); + + if (accountPageProfileInformationExpandedIsAvailable) { + final profileInformationFinder = find.byKey( + const Key('profile_information'), + ); + checkError( + 32, + find.descendant( + of: accountPageProfileInformationExpandedFinder, + matching: profileInformationFinder, + ), + findsOneWidget, + ); + } + } + }); + testWidgets("Check if profile picture is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: ProfilePic(pictureUrl: profile.profilePic!), + ), + ), + ); + + final profilePicContainerFinder = find.byKey( + const Key('profile_pic_container'), + ); + bool profilePicContainerIsAvailable = checkError( + 33, + profilePicContainerFinder, + findsOneWidget, + ); + if (profilePicContainerIsAvailable) { + bool profilePicContainerIsContainer = checkError( + 34, + profilePicContainerFinder.evaluate().first.widget, + isA(), + ); + if (profilePicContainerIsContainer) { + final profilePicContainer = + profilePicContainerFinder.evaluate().first.widget as Container; + checkError( + 35, + profilePicContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 80, maxWidth: 80), + ); + checkError( + 36, + profilePicContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 80, maxHeight: 80), + ); + checkError( + 37, + profilePicContainer.margin, + const EdgeInsets.only(left: 15, right: 30), + ); + final profilePicDecoration = + profilePicContainer.decoration as BoxDecoration; + bool profilePicDecorationIsBoxDecoration = checkError( + 38, + profilePicDecoration, + isA(), + ); + + if (profilePicDecorationIsBoxDecoration) { + final profilePicDecoration = + profilePicContainer.decoration as BoxDecoration; + checkError( + 39, + profilePicDecoration.shape, + BoxShape.circle, + ); + + bool profilePicDecorationImageIsDecorationImage = checkError( + 40, + profilePicDecoration.image, + isA(), + ); + if (profilePicDecorationImageIsDecorationImage) { + final profilePicDecorationImage = + profilePicDecoration.image as DecorationImage; + checkError(41, profilePicDecorationImage.fit, BoxFit.cover); + bool profilePicDecorationImageIsNetworkImage = checkError( + 42, + profilePicDecorationImage.image, + isA(), + ); + if (profilePicDecorationImageIsNetworkImage) { + final profilePicDecorationImageNetworkImage = + profilePicDecorationImage.image as NetworkImage; + checkError( + 43, + profilePicDecorationImageNetworkImage.url, + profile.profilePic!, + ); + } + } + } + } + } + }); + testWidgets("Check if profile informations is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: ProfileInformation(profileStats: profile.stats!), + ), + ), + ); + + final profileInformationRowFinder = find.byKey( + const Key('profile_information_row'), + ); + bool profileInformationRowIsAvailable = checkError( + 44, + profileInformationRowFinder, + findsOneWidget, + ); + if (profileInformationRowIsAvailable) { + bool profileInformationRowIsRow = checkError( + 45, profileInformationRowFinder.evaluate().first.widget, isA()); + if (profileInformationRowIsRow) { + final profileInformationRow = + profileInformationRowFinder.evaluate().first.widget as Row; + checkError( + 46, profileInformationRow.children.length, profile.stats!.length); + checkError( + 47, + profileInformationRow.mainAxisAlignment, + MainAxisAlignment.spaceAround, + ); + + profile.stats!.asMap().forEach((index, value) { + final profileInformationColumnFinder = find.byKey( + Key('profile_information_column_$index'), + ); + bool profileInformationColumnIsAvailable = checkError( + 48, + profileInformationColumnFinder, + findsOneWidget, + ); + if (profileInformationColumnIsAvailable) { + bool profileInformationColumnIsColumn = checkError( + 49, + profileInformationColumnFinder.evaluate().first.widget, + isA(), + ); + if (profileInformationColumnIsColumn) { + final profileInformationColumn = profileInformationColumnFinder + .evaluate() + .first + .widget as Column; + checkError(50, profileInformationColumn.children.length, 2); + + final profileInformationAmountTextFinder = find.byKey( + Key('profile_information_${index}_amount_text'), + ); + bool profileInformationAmountTextIsAvailable = checkError( + 51, + profileInformationAmountTextFinder, + findsOneWidget, + ); + if (profileInformationAmountTextIsAvailable) { + bool profileInformationAmountTextIsText = checkError( + 52, + profileInformationAmountTextFinder.evaluate().first.widget, + isA(), + ); + if (profileInformationAmountTextIsText) { + final profileInformationAmountText = + profileInformationAmountTextFinder.evaluate().first.widget + as Text; + checkError(53, profileInformationAmountText.data, + profile.stats![index].count.toString()); + checkError( + 54, + profileInformationAmountText.style, + const TextStyle( + fontSize: 20, + fontWeight: FontWeight.w700, + color: Colors.white), + ); + } + } + + final profileInformationLabelTextFinder = find.byKey( + Key('profile_information_${index}_label_text'), + ); + bool profileInformationLabelTextIsAvailable = checkError( + 55, + profileInformationLabelTextFinder, + findsOneWidget, + ); + if (profileInformationLabelTextIsAvailable) { + bool profileInformationLabelTextIsText = checkError( + 56, + profileInformationLabelTextFinder.evaluate().first.widget, + isA(), + ); + if (profileInformationLabelTextIsText) { + final profileInformationLabelText = + profileInformationLabelTextFinder.evaluate().first.widget + as Text; + checkError(57, profileInformationLabelText.data, + profile.stats![index].label); + checkError( + 58, + profileInformationLabelText.style, + const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w400, + color: Colors.white, + ), + ); + } + } + } + } + }); + } + } + }); + testWidgets("Check if account's name is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: AccountName(profile: profile), + ), + ), + ); + + final accountNameContainerFinder = find.byKey( + const Key('account_name_container'), + ); + bool accountNameContainerIsAvailable = checkError( + 59, + accountNameContainerFinder, + findsOneWidget, + ); + if (accountNameContainerIsAvailable) { + bool accountNameContainerIsContainer = checkError( + 60, + accountNameContainerFinder.evaluate().first.widget, + isA(), + ); + if (accountNameContainerIsContainer) { + final accountNameContainer = + accountNameContainerFinder.evaluate().first.widget as Container; + checkError( + 61, + accountNameContainer.constraints!.widthConstraints(), + const BoxConstraints( + minWidth: double.infinity, maxWidth: double.infinity), + ); + checkError( + 62, + accountNameContainer.padding, + const EdgeInsets.symmetric(horizontal: 15), + ); + checkError( + 63, + accountNameContainer.margin, + const EdgeInsets.symmetric(vertical: 10), + ); + + final accountNameColumnFinder = find.byKey( + const Key('account_name_column'), + ); + bool accountNameColumnIsAvailable = checkError( + 64, + find.descendant( + of: accountNameContainerFinder, + matching: accountNameColumnFinder), + findsOneWidget, + ); + + if (accountNameColumnIsAvailable) { + bool accountNameColumnIsColumn = checkError( + 65, + accountNameColumnFinder.evaluate().first.widget, + isA(), + ); + + if (accountNameColumnIsColumn) { + final accountNameColumn = + accountNameColumnFinder.evaluate().first.widget as Column; + checkError( + 66, + accountNameColumn.crossAxisAlignment, + CrossAxisAlignment.start, + ); + checkError(67, accountNameColumn.children.length, 2); + + final accountNameTextFinder = find.byKey( + const Key('account_name_text'), + ); + + bool accountNameTextIsAvailable = checkError( + 68, + find.descendant( + of: accountNameColumnFinder, matching: accountNameTextFinder), + findsOneWidget, + ); + + if (accountNameTextIsAvailable) { + bool accountNameTextIsText = checkError( + 69, + accountNameTextFinder.evaluate().first.widget, + isA(), + ); + + if (accountNameTextIsText) { + final accountNameText = + accountNameTextFinder.evaluate().first.widget as Text; + checkError(70, accountNameText.data, profile.name); + checkError( + 71, + accountNameText.style, + const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w400, + color: Colors.white, + ), + ); + } + } + + final accountBioText = find.byKey(const Key('account_bio_text')); + bool accountBioTextIsAvailable = checkError( + 72, + find.descendant( + of: accountNameColumnFinder, matching: accountBioText), + findsOneWidget, + ); + + if (accountBioTextIsAvailable) { + bool accountBioTextIsText = checkError( + 73, + accountBioText.evaluate().first.widget, + isA(), + ); + + if (accountBioTextIsText) { + final accountBioTextWidget = + accountBioText.evaluate().first.widget as Text; + checkError(74, accountBioTextWidget.data, profile.bio); + checkError( + 75, + accountBioTextWidget.style, + const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w400, + color: Colors.white, + ), + ); + } + } + } + } + } + } + }); + testWidgets("Check if profile buttons is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + const MaterialApp( + home: ProfileButtons(), + ), + ), + ); + + final profileButtonsPaddingFinder = find.byKey( + const Key('profile_buttons_padding'), + ); + + bool accountPageProfileButtonsPaddingIsAvailable = checkError( + 76, + profileButtonsPaddingFinder, + findsOneWidget, + ); + + if (accountPageProfileButtonsPaddingIsAvailable) { + bool accountPageProfileButtonsPaddingIsPadding = checkError( + 77, + profileButtonsPaddingFinder.evaluate().first.widget, + isA(), + ); + + if (accountPageProfileButtonsPaddingIsPadding) { + final accountPageProfileButtonsPadding = + profileButtonsPaddingFinder.evaluate().first.widget as Padding; + checkError( + 78, + accountPageProfileButtonsPadding.padding, + const EdgeInsets.symmetric(horizontal: 15), + ); + + final profileButtonsRowFinder = + find.byKey(const Key('profile_buttons_row')); + bool profileButtonsRowIsAvailable = checkError( + 79, + find.descendant( + of: profileButtonsPaddingFinder, + matching: profileButtonsRowFinder), + findsOneWidget, + ); + + if (profileButtonsRowIsAvailable) { + bool profileButtonsRowIsRow = checkError( + 80, + profileButtonsRowFinder.evaluate().first.widget, + isA(), + ); + + if (profileButtonsRowIsRow) { + final profileButtonsRow = + profileButtonsRowFinder.evaluate().first.widget as Row; + checkError( + 81, + profileButtonsRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween, + ); + checkError(82, profileButtonsRow.children.length, 5); + + final profileButtonsEditProfileButtonExpandedFinder = find.byKey( + const Key('profile_buttons_edit_profile_button_expanded'), + ); + bool profileButtonsEditProfileButtonExpandedIsAvailable = + checkError( + 83, + find.descendant( + of: profileButtonsRowFinder, + matching: profileButtonsEditProfileButtonExpandedFinder, + ), + findsOneWidget, + ); + + if (profileButtonsEditProfileButtonExpandedIsAvailable) { + checkError( + 84, + profileButtonsEditProfileButtonExpandedFinder + .evaluate() + .first + .widget, + isA(), + ); + + final profileButtonsEditProfileButtonFinder = find.byKey( + const Key('profile_buttons_edit_profile_button'), + ); + bool profileButtonsEditProfileButtonIsAvailable = checkError( + 85, + find.descendant( + of: profileButtonsEditProfileButtonExpandedFinder, + matching: profileButtonsEditProfileButtonFinder), + findsOneWidget, + ); + if (profileButtonsEditProfileButtonIsAvailable) { + checkError( + 86, + profileButtonsEditProfileButtonFinder.evaluate().first.widget, + isA(), + ); + + final profileButtonsEditProfileButtonTextFinder = find.byKey( + const Key('profile_buttons_edit_profile_button_text'), + ); + bool profileButtonsEditProfileButtonTextIsAvailable = + checkError( + 87, + find.descendant( + of: profileButtonsEditProfileButtonFinder, + matching: profileButtonsEditProfileButtonTextFinder), + findsOneWidget, + ); + if (profileButtonsEditProfileButtonTextIsAvailable) { + bool profileButtonsEditProfileButtonTextIsText = checkError( + 88, + profileButtonsEditProfileButtonTextFinder + .evaluate() + .first + .widget, + isA(), + ); + if (profileButtonsEditProfileButtonTextIsText) { + final profileButtonsEditProfileButtonText = + profileButtonsEditProfileButtonTextFinder + .evaluate() + .first + .widget as Text; + checkError( + 89, + profileButtonsEditProfileButtonText.data, + 'Edit Profile', + ); + checkError( + 90, + profileButtonsEditProfileButtonText.style, + const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + ); + } + } + } + } + + final profileButtonsShareProfileButtonExpandedFinder = find.byKey( + const Key('profile_buttons_share_profile_button_expanded'), + ); + bool profileButtonsShareProfileButtonExpandedIsAvailable = + checkError( + 91, + find.descendant( + of: profileButtonsRowFinder, + matching: profileButtonsShareProfileButtonExpandedFinder, + ), + findsOneWidget, + ); + if (profileButtonsShareProfileButtonExpandedIsAvailable) { + checkError( + 92, + profileButtonsShareProfileButtonExpandedFinder + .evaluate() + .first + .widget, + isA(), + ); + + final profileButtonsShareProfileButtonFinder = find.byKey( + const Key('profile_buttons_share_profile_button'), + ); + bool profileButtonsShareProfileButtonIsAvailable = checkError( + 93, + find.descendant( + of: profileButtonsShareProfileButtonExpandedFinder, + matching: profileButtonsShareProfileButtonFinder), + findsOneWidget, + ); + if (profileButtonsShareProfileButtonIsAvailable) { + checkError( + 94, + profileButtonsShareProfileButtonFinder + .evaluate() + .first + .widget, + isA(), + ); + + final profileButtonsShareProfileButtonTextFinder = find.byKey( + const Key('profile_buttons_share_profile_button_text'), + ); + bool profileButtonsShareProfileButtonTextIsAvailable = + checkError( + 95, + find.descendant( + of: profileButtonsShareProfileButtonFinder, + matching: profileButtonsShareProfileButtonTextFinder), + findsOneWidget, + ); + if (profileButtonsShareProfileButtonTextIsAvailable) { + bool profileButtonsShareProfileButtonTextIsText = checkError( + 96, + profileButtonsShareProfileButtonTextFinder + .evaluate() + .first + .widget, + isA(), + ); + if (profileButtonsShareProfileButtonTextIsText) { + final profileButtonsShareProfileButtonText = + profileButtonsShareProfileButtonTextFinder + .evaluate() + .first + .widget as Text; + checkError( + 97, + profileButtonsShareProfileButtonText.data, + 'Share profile', + ); + checkError( + 98, + profileButtonsShareProfileButtonText.style, + const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + ); + } + } + } + } + + final profileButtonsDiscoverPeopleButtonFinder = find.byKey( + const Key('profile_buttons_discover_people_button'), + ); + bool profileButtonsDiscoverPeopleButtonIsAvailable = checkError( + 99, + find.descendant( + of: profileButtonsRowFinder, + matching: profileButtonsDiscoverPeopleButtonFinder), + findsOneWidget, + ); + if (profileButtonsDiscoverPeopleButtonIsAvailable) { + checkError( + 100, + profileButtonsDiscoverPeopleButtonFinder + .evaluate() + .first + .widget, + isA(), + ); + + final profileButtonsDiscoverPeopleIconFinder = find.byKey( + const Key('profile_buttons_discover_people_icon'), + ); + bool profileButtonsDiscoverPeopleIconIsAvailable = checkError( + 101, + find.descendant( + of: profileButtonsDiscoverPeopleButtonFinder, + matching: profileButtonsDiscoverPeopleIconFinder), + findsOneWidget, + ); + if (profileButtonsDiscoverPeopleIconIsAvailable) { + bool profileButtonsDiscoverPeopleIconIsIcon = checkError( + 102, + profileButtonsDiscoverPeopleIconFinder + .evaluate() + .first + .widget, + isA(), + ); + if (profileButtonsDiscoverPeopleIconIsIcon) { + final profileButtonsDiscoverPeopleIcon = + profileButtonsDiscoverPeopleIconFinder + .evaluate() + .first + .widget as Icon; + checkError( + 103, + profileButtonsDiscoverPeopleIcon.icon, + Icons.person_add_outlined, + ); + checkError( + 104, + profileButtonsDiscoverPeopleIcon.color, + Colors.white, + ); + } + } + } + } + } + } + } + }); + testWidgets("Check if Grey buttons is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + const mockKey = Key('grey_button'); + const mockWidget = Text('Grey Button'); + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: GreyButton( + key: mockKey, + onPressed: () {}, + child: mockWidget, + ), + ), + ), + ); + + final greyButtonElevatedButtonFinder = find.byKey( + Key('${mockKey}_elevated_button'), + ); + bool greyButtonElevatedButtonIsAvailable = checkError( + 105, + greyButtonElevatedButtonFinder, + findsOneWidget, + ); + if (greyButtonElevatedButtonIsAvailable) { + bool greyButtonElevatedButtonIsElevatedButton = checkError( + 106, + greyButtonElevatedButtonFinder.evaluate().first.widget, + isA(), + ); + if (greyButtonElevatedButtonIsElevatedButton) { + final greyButtonElevatedButton = greyButtonElevatedButtonFinder + .evaluate() + .first + .widget as ElevatedButton; + try { + checkError( + 107, + greyButtonElevatedButton.style!.backgroundColor!.resolve(states), + Colors.grey[800], + ); + } catch (e) { + debugPrint( + "Account Page Test-107 failed: backgroundColor is not set", + ); + } + + try { + checkError( + 108, + greyButtonElevatedButton.style!.minimumSize!.resolve(states), + const Size(0, 30), + ); + } catch (e) { + debugPrint( + "Account Page Test-108 failed: minimumSize is not set", + ); + } + + try { + checkError( + 109, + greyButtonElevatedButton.style!.shape!.resolve(states), + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5), + ), + ); + } catch (e) { + debugPrint( + "Account Page Test-109 failed: shape is not set", + ); + } + } + } + }); + testWidgets("Check if Highlight list is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: HighlightList(stories: stories), + ), + ), + ); + + final highlightListScrollViewFinder = find.byKey( + const Key('highlight_list_scroll_view'), + ); + + bool highlightListScrollViewIsAvailable = checkError( + 110, + highlightListScrollViewFinder, + findsOneWidget, + ); + + if (highlightListScrollViewIsAvailable) { + bool highlightListScrollViewIsScrollView = checkError( + 111, + highlightListScrollViewFinder.evaluate().first.widget, + isA(), + ); + if (highlightListScrollViewIsScrollView) { + final highlightListScrollView = highlightListScrollViewFinder + .evaluate() + .first + .widget as SingleChildScrollView; + checkError( + 112, + highlightListScrollView.scrollDirection, + Axis.horizontal, + ); + checkError( + 113, + highlightListScrollView.padding, + const EdgeInsets.only(left: 15, top: 10, bottom: 10), + ); + } + final highlightListParentRowFinder = find.byKey( + const Key("highlight_list_parent_row"), + ); + bool highlightListParentRowIsAvailable = checkError( + 114, + find.descendant( + of: highlightListScrollViewFinder, + matching: highlightListParentRowFinder, + ), + findsOneWidget, + ); + if (highlightListParentRowIsAvailable) { + checkError( + 115, + highlightListParentRowFinder.evaluate().first.widget, + isA(), + ); + final highlightListChildRowFinder = find.byKey( + const Key("highlight_list_child_row"), + ); + bool highlightListChildRowIsAvailable = checkError( + 116, + find.descendant( + of: highlightListParentRowFinder, + matching: highlightListChildRowFinder, + ), + findsOneWidget, + ); + if (highlightListChildRowIsAvailable) { + bool highlightListChildRowIsRow = checkError( + 117, + highlightListChildRowFinder.evaluate().first.widget, + isA(), + ); + if (highlightListChildRowIsRow) { + final highlightListChildRow = + highlightListChildRowFinder.evaluate().first.widget as Row; + bool highlightItemsFinder = checkError( + 118, + highlightListChildRow.children.length, + stories.length, + ); + + if (highlightItemsFinder) { + stories.asMap().forEach((key, value) { + final highlightItemFinder = find.byKey( + Key("highlight_item_$key"), + ); + bool highlightItemIsAvailable = checkError( + 119, + find.descendant( + of: highlightListChildRowFinder, + matching: highlightItemFinder, + ), + findsOneWidget, + ); + + if (highlightItemIsAvailable) { + bool highlightItemIsHighlightItem = checkError( + 120, + highlightItemFinder.evaluate().first.widget, + isA(), + ); + if (highlightItemIsHighlightItem) { + final highlightItem = highlightItemFinder + .evaluate() + .first + .widget as HighlightItem; + checkError( + 121, + highlightItem.img, + value["img"], + ); + checkError( + 122, + highlightItem.name, + value["name"], + ); + } + } + }); + } + } + } + + final highightListAddHighlightFinder = find.byKey( + const Key("highlight_list_add_highlight"), + ); + bool highightAddHighlightIsAvailable = checkError( + 123, + find.descendant( + of: highlightListParentRowFinder, + matching: highightListAddHighlightFinder, + ), + findsOneWidget, + ); + + if (highightAddHighlightIsAvailable) { + bool highightAddHighlightIsPadding = checkError( + 124, + highightListAddHighlightFinder.evaluate().first.widget, + isA(), + ); + if (highightAddHighlightIsPadding) { + final highightAddHighlight = highightListAddHighlightFinder + .evaluate() + .first + .widget as Padding; + checkError( + 125, + highightAddHighlight.padding, + const EdgeInsets.only(right: 10, bottom: 10), + ); + } + + final highlightListAddHighlightColumnFinder = find.byKey( + const Key("highlight_list_add_highlight_column"), + ); + bool highlightListAddHighlightColumnIsAvailable = checkError( + 126, + find.descendant( + of: highightListAddHighlightFinder, + matching: highlightListAddHighlightColumnFinder, + ), + findsOneWidget, + ); + if (highlightListAddHighlightColumnIsAvailable) { + bool highlightListAddHighlightColumnIsColumn = checkError( + 127, + highlightListAddHighlightColumnFinder.evaluate().first.widget, + isA(), + ); + if (highlightListAddHighlightColumnIsColumn) { + final highlightListAddHighlightColumn = + highlightListAddHighlightColumnFinder.evaluate().first.widget + as Column; + checkError( + 129, + highlightListAddHighlightColumn.children.length, + 2, + ); + // final highlightListAddHighlightIconFinder = find.byKey( + // const Key("highlight_list_add_highlight_icon"), + // ); + // bool highlightListAddHighlightIconIsAvailable = checkError( + // 130, + // find.descendant( + // of: highlightListAddHighlightColumnFinder, + // matching: highlightListAddHighlightIconFinder, + // ), + // findsOneWidget, + // ); + // if (highlightListAddHighlightIconIsAvailable) { + // bool highlightListAddHighlightIconIsIcon = checkError( + // 131, + // highlightListAddHighlightIconFinder.evaluate().first.widget, + // isA(), + // ); + // if (highlightListAddHighlightIconIsIcon) { + // final highlightListAddHighlightIcon = + // highlightListAddHighlightIconFinder + // .evaluate() + // .first + // .widget as Icon; + // checkError( + // 132, + // highlightListAddHighlightIcon.icon, + // Icons.add, + // ); + // checkError( + // 133, + // highlightListAddHighlightIcon.color, + // Colors.white, + // ); + // } + // } + // final highlightListAddHighlightTextFinder = find.byKey( + // const Key("highlight_list_add_highlight_text"), + // ); + // bool highlightListAddHighlightTextIsAvailable = checkError( + // 134, + // find.descendant( + // of: highlightListAddHighlightColumnFinder, + // matching: highlightListAddHighlightTextFinder, + // ), + // findsOneWidget, + // ); + // if (highlightListAddHighlightTextIsAvailable) { + // bool highlightListAddHighlightTextIsText = checkError( + // 135, + // highlightListAddHighlightTextFinder.evaluate().first.widget, + // isA(), + // ); + // if (highlightListAddHighlightTextIsText) { + // final highlightListAddHighlightText = + // highlightListAddHighlightTextFinder + // .evaluate() + // .first + // .widget as Text; + // checkError( + // 136, + // highlightListAddHighlightText.data, + // "New", + // ); + // } + // } + } + + final highlightListAddHighlightContainerFinder = find.byKey( + const Key("highlight_list_add_highlight_container"), + ); + bool highlightAddHighlightContainerIsAvailable = checkError( + 137, + find.descendant( + of: highlightListAddHighlightColumnFinder, + matching: highlightListAddHighlightContainerFinder, + ), + findsOneWidget, + ); + if (highlightAddHighlightContainerIsAvailable) { + bool highlightAddHighlightContainerIsContainer = checkError( + 138, + highlightListAddHighlightContainerFinder + .evaluate() + .first + .widget, + isA(), + ); + if (highlightAddHighlightContainerIsContainer) { + final highlightAddHighlightContainer = + highlightListAddHighlightContainerFinder + .evaluate() + .first + .widget as Container; + checkError( + 139, + highlightAddHighlightContainer.padding, + const EdgeInsets.all(3), + ); + checkError( + 140, + highlightAddHighlightContainer.margin, + const EdgeInsets.only(bottom: 8), + ); + checkError( + 141, + highlightAddHighlightContainer.constraints! + .widthConstraints(), + const BoxConstraints(minWidth: 68, maxWidth: 68), + ); + checkError( + 142, + highlightAddHighlightContainer.constraints! + .heightConstraints(), + const BoxConstraints(minHeight: 68, maxHeight: 68), + ); + + bool highlightAddHighlightContainerDecorationBoxDecoration = + checkError( + 143, + highlightAddHighlightContainer.decoration, + isA(), + ); + if (highlightAddHighlightContainerDecorationBoxDecoration) { + final highlightAddHighlightContainerDecoration = + highlightAddHighlightContainer.decoration + as BoxDecoration; + checkError( + 144, + highlightAddHighlightContainerDecoration.shape, + BoxShape.circle); + checkError( + 145, + highlightAddHighlightContainerDecoration.border, + Border.all(color: Colors.white, width: 1), + ); + } + } + + final highlightListAddHighlightIconContainerFinder = find.byKey( + const Key("highlight_list_add_highlight_icon_container"), + ); + + bool highlightListAddHighlightIconContainerIsAvailable = + checkError( + 146, + find.descendant( + of: highlightListAddHighlightContainerFinder, + matching: highlightListAddHighlightIconContainerFinder, + ), + findsOneWidget, + ); + if (highlightListAddHighlightIconContainerIsAvailable) { + bool highlightListAddHighlightIconContainerIsContainer = + checkError( + 147, + highlightListAddHighlightIconContainerFinder + .evaluate() + .first + .widget, + isA(), + ); + if (highlightListAddHighlightIconContainerIsContainer) { + final highlightListAddHighlightIconContainer = + highlightListAddHighlightIconContainerFinder + .evaluate() + .first + .widget as Container; + bool highlightListAddHighlightIconContainerIsBoxDecoration = + checkError( + 148, + highlightListAddHighlightIconContainer.decoration, + isA(), + ); + if (highlightListAddHighlightIconContainerIsBoxDecoration) { + final highlightListAddHighlightIconContainerDecoration = + highlightListAddHighlightIconContainer.decoration + as BoxDecoration; + checkError( + 149, + highlightListAddHighlightIconContainerDecoration.shape, + BoxShape.circle, + ); + checkError( + 150, + highlightListAddHighlightIconContainerDecoration.border, + Border.all(color: Colors.black, width: 2), + ); + } + } + + final highlightListAddHighlightIconFinder = find.byKey( + const Key("highlight_list_add_highlight_icon"), + ); + bool highlightListAddHighlightIconIsAvailable = checkError( + 151, + find.descendant( + of: highlightListAddHighlightIconContainerFinder, + matching: highlightListAddHighlightIconFinder, + ), + findsOneWidget, + ); + + if (highlightListAddHighlightIconIsAvailable) { + bool highlightListAddHighlightIconIsIcon = checkError( + 152, + highlightListAddHighlightIconFinder.evaluate().first.widget, + isA(), + ); + if (highlightListAddHighlightIconIsIcon) { + final highlightListAddHighlightIcon = + highlightListAddHighlightIconFinder + .evaluate() + .first + .widget as Icon; + checkError( + 153, + highlightListAddHighlightIcon.icon, + Icons.add, + ); + checkError( + 154, + highlightListAddHighlightIcon.color, + Colors.white, + ); + } + } + } + } + + final highlightListAddHighlightTextSizedBoxFinder = find.byKey( + const Key("highlight_list_add_highlight_text_sized_box"), + ); + bool highlightListAddHighlightTextSizedBoxIsAvailable = checkError( + 155, + find.descendant( + of: highlightListAddHighlightColumnFinder, + matching: highlightListAddHighlightTextSizedBoxFinder, + ), + findsOneWidget, + ); + + if (highlightListAddHighlightTextSizedBoxIsAvailable) { + bool highlightListAddHighlightTextSizedBoxIsSizedBox = checkError( + 156, + highlightListAddHighlightTextSizedBoxFinder + .evaluate() + .first + .widget, + isA(), + ); + if (highlightListAddHighlightTextSizedBoxIsSizedBox) { + final highlightListAddHighlightTextSizedBox = + highlightListAddHighlightTextSizedBoxFinder + .evaluate() + .first + .widget as SizedBox; + checkError( + 157, highlightListAddHighlightTextSizedBox.width, 70); + } + + final highlightListAddHighlightTextFinder = find.byKey( + const Key("highlight_list_add_highlight_text"), + ); + bool highlightListAddHighlightTextIsAvailable = checkError( + 158, + find.descendant( + of: highlightListAddHighlightTextSizedBoxFinder, + matching: highlightListAddHighlightTextFinder, + ), + findsOneWidget, + ); + + if (highlightListAddHighlightTextIsAvailable) { + bool highlightListAddHighlightTextIsText = checkError( + 159, + highlightListAddHighlightTextFinder.evaluate().first.widget, + isA(), + ); + if (highlightListAddHighlightTextIsText) { + final highlightListAddHighlightText = + highlightListAddHighlightTextFinder + .evaluate() + .first + .widget as Text; + checkError(160, highlightListAddHighlightText.data, "New"); + checkError( + 161, + highlightListAddHighlightText.overflow, + TextOverflow.ellipsis, + ); + checkError( + 162, + highlightListAddHighlightText.textAlign, + TextAlign.center, + ); + bool highlightListAddHighlightTextIsTextStyle = checkError( + 163, + highlightListAddHighlightText.style, + isA(), + ); + if (highlightListAddHighlightTextIsTextStyle) { + final highlightListAddHighlightTextStyle = + highlightListAddHighlightText.style as TextStyle; + checkError( + 164, + highlightListAddHighlightTextStyle.color, + Colors.white, + ); + } + } + } + } + } + } + } + } + }); + testWidgets("Check if Highlight Item is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + final img = stories[0]["img"]; + final name = stories[0]["name"]; + await widgetTester.pumpWidget( + MaterialApp( + home: HighlightItem( + img: img, + name: name, + ), + ), + ); + + final highlightItemPaddingFinder = find.byKey( + const Key("highlight_item_padding"), + ); + bool highlightItemPaddingIsAvailable = checkError( + 165, + find.descendant( + of: find.byType(HighlightItem), + matching: highlightItemPaddingFinder, + ), + findsOneWidget, + ); + + if (highlightItemPaddingIsAvailable) { + bool highlightItemPaddingIsPadding = checkError( + 166, + highlightItemPaddingFinder.evaluate().first.widget, + isA(), + ); + if (highlightItemPaddingIsPadding) { + final highlightItemPadding = + highlightItemPaddingFinder.evaluate().first.widget as Padding; + checkError( + 167, + highlightItemPadding.padding, + const EdgeInsets.only(right: 10, bottom: 10), + ); + } + final highlightItemColumnFinder = find.byKey( + const Key("highlight_item_column"), + ); + bool highlightItemColumnIsAvailable = checkError( + 168, + find.descendant( + of: highlightItemPaddingFinder, + matching: highlightItemColumnFinder, + ), + findsOneWidget, + ); + + if (highlightItemColumnIsAvailable) { + bool highlightItemColumnIsColumn = checkError( + 169, + highlightItemColumnFinder.evaluate().first.widget, + isA(), + ); + if (highlightItemColumnIsColumn) { + final highlightItemColumn = + highlightItemColumnFinder.evaluate().first.widget as Column; + checkError(170, highlightItemColumn.children.length, 2); + } + + final highlightItemContainerFinder = find.byKey( + const Key("highlight_item_container"), + ); + bool highlightItemContainerIsAvailable = checkError( + 171, + find.descendant( + of: highlightItemColumnFinder, + matching: highlightItemContainerFinder, + ), + findsOneWidget, + ); + if (highlightItemContainerIsAvailable) { + bool highlightItemContainerIsContainer = checkError( + 172, + highlightItemContainerFinder.evaluate().first.widget, + isA(), + ); + if (highlightItemContainerIsContainer) { + final highlightItemContainer = highlightItemContainerFinder + .evaluate() + .first + .widget as Container; + checkError( + 173, + highlightItemContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 68, maxWidth: 68), + ); + checkError( + 174, + highlightItemContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 68, maxHeight: 68), + ); + checkError( + 175, + highlightItemContainer.padding, + const EdgeInsets.all(3.0), + ); + checkError( + 176, + highlightItemContainer.margin, + const EdgeInsets.only(bottom: 8), + ); + + bool highlightItemContainerDecorationIsBoxDecoration = checkError( + 177, + highlightItemContainer.decoration, + isA(), + ); + + if (highlightItemContainerDecorationIsBoxDecoration) { + final highlightItemContainerDecoration = + highlightItemContainer.decoration as BoxDecoration; + checkError( + 178, highlightItemContainerDecoration.shape, BoxShape.circle); + checkError( + 179, + highlightItemContainerDecoration.border, + Border.all(color: Colors.grey[800]!, width: 1), + ); + } + } + } + final highlightItemImageContainerFinder = find.byKey( + const Key("highlight_item_image_container"), + ); + bool highlightItemImageContainerIsAvailable = checkError( + 180, + find.descendant( + of: highlightItemContainerFinder, + matching: highlightItemImageContainerFinder, + ), + findsOneWidget, + ); + if (highlightItemImageContainerIsAvailable) { + bool highlightItemImageContainerIsContainer = checkError( + 181, + highlightItemImageContainerFinder.evaluate().first.widget, + isA(), + ); + if (highlightItemImageContainerIsContainer) { + final highlightItemImageContainer = + highlightItemImageContainerFinder.evaluate().first.widget + as Container; + bool highlightItemImageContainerDecorationIsBoxDecoration = + checkError(182, highlightItemImageContainer.decoration, + isA()); + if (highlightItemImageContainerDecorationIsBoxDecoration) { + final highlightItemImageContainerDecoration = + highlightItemImageContainer.decoration as BoxDecoration; + checkError(183, highlightItemImageContainerDecoration.shape, + BoxShape.circle); + checkError( + 184, + highlightItemImageContainerDecoration.border, + Border.all(color: Colors.black, width: 2), + ); + bool highlightItemImageContainerDecorationImageIsDecorationImage = + checkError( + 185, + highlightItemImageContainerDecoration.image, + isA(), + ); + + if (highlightItemImageContainerDecorationImageIsDecorationImage) { + final highlightItemImageContainerDecorationImage = + highlightItemImageContainerDecoration.image + as DecorationImage; + checkError(186, highlightItemImageContainerDecorationImage.fit, + BoxFit.cover); + bool highlightItemImageContainerDecorationImageIsNetworkImage = + checkError( + 187, + highlightItemImageContainerDecorationImage.image, + isA(), + ); + + if (highlightItemImageContainerDecorationImageIsNetworkImage) { + final highlightItemImageContainerDecorationImageNetworkImage = + highlightItemImageContainerDecorationImage.image + as NetworkImage; + checkError( + 188, + highlightItemImageContainerDecorationImageNetworkImage.url, + img, + ); + } + } + } + } + } + + final highlightItemTextSizedBoxFinder = find.byKey( + const Key("highlight_item_text_sized_box"), + ); + bool highlightItemTextSizedBoxIsAvailable = checkError( + 189, + find.descendant( + of: highlightItemColumnFinder, + matching: highlightItemTextSizedBoxFinder, + ), + findsOneWidget, + ); + + if (highlightItemTextSizedBoxIsAvailable) { + bool highlightItemTextSizedBoxIsSizedBox = checkError( + 190, + highlightItemTextSizedBoxFinder.evaluate().first.widget, + isA(), + ); + if (highlightItemTextSizedBoxIsSizedBox) { + final highlightItemTextSizedBox = highlightItemTextSizedBoxFinder + .evaluate() + .first + .widget as SizedBox; + checkError(191, highlightItemTextSizedBox.width, 70); + } + final highlightItemTextFinder = find.byKey( + const Key("highlight_item_text"), + ); + bool highlightItemTextIsAvailable = checkError( + 192, + find.descendant( + of: highlightItemTextSizedBoxFinder, + matching: highlightItemTextFinder, + ), + findsOneWidget, + ); + if (highlightItemTextIsAvailable) { + bool highlightItemTextIsText = checkError( + 193, + highlightItemTextFinder.evaluate().first.widget, + isA(), + ); + if (highlightItemTextIsText) { + final highlightItemText = + highlightItemTextFinder.evaluate().first.widget as Text; + checkError( + 194, highlightItemText.overflow, TextOverflow.ellipsis); + checkError(195, highlightItemText.textAlign, TextAlign.center); + bool highlightItemTextIsTextStyle = checkError( + 196, + highlightItemText.style, + isA(), + ); + if (highlightItemTextIsTextStyle) { + final highlightItemTextStyle = + highlightItemText.style as TextStyle; + checkError(197, highlightItemTextStyle.color, Colors.white); + } + checkError(198, highlightItemText.data, name); + } + } + } + } + } + }); + testWidgets("Check if Account tab is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + const pageIndex = 0; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: AccountTab( + pageIndex: pageIndex, + updateIndex: (updateIndex) {}, + ), + ), + ), + ); + + final accountTabRowFinder = find.byKey( + const Key("account_tab_row"), + ); + bool accountTabRowIsAvailable = checkError( + 199, + accountTabRowFinder, + findsOneWidget, + ); + if (accountTabRowIsAvailable) { + bool accountTabRowIsRow = checkError( + 200, + accountTabRowFinder.evaluate().first.widget, + isA(), + ); + if (accountTabRowIsRow) { + final accountTabRow = + accountTabRowFinder.evaluate().first.widget as Row; + checkError(201, accountTabRow.children.length, tabs.length); + } + + tabs.asMap().forEach((key, value) { + final accountTabDecoratedBoxFinder = find.byKey( + Key("account_tab_decorated_box_$key"), + ); + bool accountTabDecoratedBoxIsAvailable = checkError( + 202, + find.descendant( + of: accountTabRowFinder, + matching: accountTabDecoratedBoxFinder, + ), + findsOneWidget, + ); + + if (accountTabDecoratedBoxIsAvailable) { + bool accountTabDecoratedBoxIsDecoratedBox = checkError( + 203, + accountTabDecoratedBoxFinder.evaluate().first.widget, + isA(), + ); + if (accountTabDecoratedBoxIsDecoratedBox) { + final accountTabDecoratedBox = accountTabDecoratedBoxFinder + .evaluate() + .first + .widget as DecoratedBox; + bool accountTabDecoratedBoxDecorationIsBoxDecoration = checkError( + 204, + accountTabDecoratedBox.decoration, + isA(), + ); + if (accountTabDecoratedBoxDecorationIsBoxDecoration) { + final accountTabDecoratedBoxDecoration = + accountTabDecoratedBox.decoration as BoxDecoration; + bool accountTabDecoratedBoxDecorationBorderIsBorder = checkError( + 205, + accountTabDecoratedBoxDecoration.border, + isA(), + ); + if (accountTabDecoratedBoxDecorationBorderIsBorder) { + final accountTabDecoratedBoxDecorationBorder = + accountTabDecoratedBoxDecoration.border as Border; + bool accountTabDecoratedBoxDecorationBorderBottomIsBorderSide = + checkError( + 206, + accountTabDecoratedBoxDecorationBorder.bottom, + isA(), + ); + if (accountTabDecoratedBoxDecorationBorderBottomIsBorderSide) { + final accountTabDecoratedBoxDecorationBorderBottom = + accountTabDecoratedBoxDecorationBorder.bottom; + checkError( + 207, + accountTabDecoratedBoxDecorationBorderBottom.color, + (pageIndex == key) ? Colors.white : Colors.transparent, + ); + checkError( + 208, + accountTabDecoratedBoxDecorationBorderBottom.width, + 2, + ); + } + } + } + } + final accountTabElevatedButtonFinder = find.byKey( + Key("account_tab_elevated_button_$key"), + ); + bool accountTabElevatedButtonIsAvailable = checkError( + 209, + find.descendant( + of: accountTabDecoratedBoxFinder, + matching: accountTabElevatedButtonFinder, + ), + findsOneWidget, + ); + if (accountTabElevatedButtonIsAvailable) { + bool accountTabElevatedButtonIsElevatedButton = checkError( + 210, + accountTabElevatedButtonFinder.evaluate().first.widget, + isA(), + ); + if (accountTabElevatedButtonIsElevatedButton) { + final accountTabElevatedButton = accountTabElevatedButtonFinder + .evaluate() + .first + .widget as ElevatedButton; + bool accountTabElevatedButtonStyleIsButtonStyle = checkError( + 211, + accountTabElevatedButton.style, + isA(), + ); + if (accountTabElevatedButtonStyleIsButtonStyle) { + final accountTabElevatedButtonStyle = + accountTabElevatedButton.style as ButtonStyle; + checkError( + 212, + accountTabElevatedButtonStyle.backgroundColor! + .resolve(states), + Colors.transparent, + ); + checkError( + 213, + accountTabElevatedButtonStyle.elevation!.resolve(states), + 0, + ); + } + } + final accountTabIconFinder = find.byKey( + Key("account_tab_icon_$key"), + ); + bool accountTabIconIsAvailable = checkError( + 214, + find.descendant( + of: accountTabElevatedButtonFinder, + matching: accountTabIconFinder, + ), + findsOneWidget, + ); + if (accountTabIconIsAvailable) { + bool accountTabIconIsIcon = checkError( + 215, + accountTabIconFinder.evaluate().first.widget, + isA(), + ); + if (accountTabIconIsIcon) { + final accountTabIcon = + accountTabIconFinder.evaluate().first.widget as Icon; + checkError(216, accountTabIcon.color, Colors.white); + checkError(217, accountTabIcon.icon, tabs[key]['icon']); + } + } + } + } + }); + } + }); + testWidgets('Check if Account posts thumbnail is present', + (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + const String imageUrl = "https://picsum.photos/250?image=9"; + // mock screen size + tester.binding.window.physicalSizeTestValue = const Size(375, 812); + await mockNetworkImagesFor( + () => tester.pumpWidget( + const MaterialApp( + home: PostThumbnail(imageUrl: imageUrl), + ), + ), + ); + + final postThumbnailContainerFinder = find.byKey( + const Key(imageUrl), + ); + checkError(218, postThumbnailContainerFinder, findsOneWidget); + + final postThumbnailContainer = + postThumbnailContainerFinder.evaluate().single.widget as Container; + checkError(219, postThumbnailContainer.decoration, isA()); + + final postThumbnailContainerDecoration = + postThumbnailContainer.decoration as BoxDecoration; + checkError( + 220, + postThumbnailContainerDecoration.image, + isA(), + ); + + final postThumbnailContainerDecorationImage = + postThumbnailContainerDecoration.image as DecorationImage; + checkError( + 221, + postThumbnailContainerDecorationImage.image, + isA(), + ); + checkError( + 222, + postThumbnailContainerDecorationImage.fit, + BoxFit.cover, + ); + + final postThumbnailContainerDecorationImageNetworkImage = + postThumbnailContainerDecorationImage.image as NetworkImage; + checkError( + 223, + postThumbnailContainerDecorationImageNetworkImage.url, + imageUrl, + ); + }); + + testWidgets('Check if Bottom Navbar is present', (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: AccountPage( + posts: posts, + stories: stories, + profileData: profileJson, + ), + ), + ), + ); + + int pageIndex = 4; + + List bottomItems = [ + pageIndex == 0 + ? "assets/images/home_active_icon.svg" + : "assets/images/home_icon.svg", + pageIndex == 1 + ? "assets/images/search_active_icon.svg" + : "assets/images/search_icon.svg", + pageIndex == 2 + ? "assets/images/upload_active_icon.svg" + : "assets/images/upload_icon.svg", + pageIndex == 3 + ? "assets/images/love_active_icon.svg" + : "assets/images/love_icon.svg", + pageIndex == 4 + ? "assets/images/account_active_icon.svg" + : "assets/images/account_icon.svg", + ]; + + final bottomNavigationBarContainer = + find.byKey(const Key('bottom_navigation_bar_container')); + checkError(224, bottomNavigationBarContainer, findsOneWidget); + + final bottomNavigationBarContainerFinder = + bottomNavigationBarContainer.evaluate().first.widget as Container; + checkError( + 225, bottomNavigationBarContainerFinder.constraints!.maxHeight, 55); + checkError(226, bottomNavigationBarContainerFinder.constraints!.maxWidth, + double.infinity); + checkError(227, bottomNavigationBarContainerFinder.color, Colors.black); + checkError(228, bottomNavigationBarContainerFinder.padding, + const EdgeInsets.only(left: 20, right: 20, bottom: 20, top: 15)); + + final bottomNavigationBarRowFinder = + find.byKey(const Key('bottom_navigation_bar_row')); + checkError( + 229, + find.descendant( + of: bottomNavigationBarContainer, + matching: bottomNavigationBarRowFinder), + findsOneWidget); + + final bottomNavigationBarRow = + bottomNavigationBarRowFinder.evaluate().first.widget as Row; + checkError(230, bottomNavigationBarRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween); + checkError(231, bottomNavigationBarRow.children, hasLength(5)); + + bottomItems.asMap().forEach((index, value) { + final bottomItem = bottomNavigationBarRow.children[index] as InkWell; + checkError(232, bottomItem.onTap, isA()); + checkError(233, bottomItem.child, isA()); + + final bottomItemSvgPicture = bottomItem.child as SvgPicture; + checkError(234, bottomItemSvgPicture.pictureProvider.runtimeType, + ExactAssetPicture); + checkError(235, bottomItemSvgPicture.width, 27); + final bottomItemSvgPicturePictureProvider = + bottomItemSvgPicture.pictureProvider as ExactAssetPicture; + checkError(236, bottomItemSvgPicturePictureProvider.assetName, + bottomItems[index]); + }); + }); +} diff --git a/clone-instagram-login-Refactoring/test/calculator_test.dart b/clone-instagram-login-Refactoring/test/calculator_test.dart new file mode 100644 index 0000000..b128e0d --- /dev/null +++ b/clone-instagram-login-Refactoring/test/calculator_test.dart @@ -0,0 +1,39 @@ +import 'package:example_widget_testing/app/modules/calculator.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network_image_mock/network_image_mock.dart'; + +import 'test_library.dart'; + +void main() { + testWidgets('Check if Calculator is functioning', + (WidgetTester tester) async { + FlutterError.onError = customFlutterErrorHandler; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + const MaterialApp( + home: SimpleCalculator(), + ), + ), + ); + + const variableA = '2'; + const variableB = '3'; + const result = '5'; + final variableAField = find.byKey(const Key('variableA')); + final variableBField = find.byKey(const Key('variableB')); + var resultTextFinder = find.byKey(const Key('result')); + checkByKeyFindOneWidget(resultTextFinder); + + await tester.enterText(variableAField, variableA); + await tester.enterText(variableBField, variableB); + await tester.tap(find.byKey(const Key('addButton'))); + await tester.pumpAndSettle(); + + var resultText = resultTextFinder.evaluate().first.widget as Text; + checkByKeyIsWidget(resultText, isA()); + // expect(find.text(result), findsOneWidget); + checkWidgetProperty("data", resultTextFinder, resultText.data, result); + }); +} diff --git a/clone-instagram-login-Refactoring/test/helper.dart b/clone-instagram-login-Refactoring/test/helper.dart new file mode 100644 index 0000000..906fa9a --- /dev/null +++ b/clone-instagram-login-Refactoring/test/helper.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +void ignoreOverflowErrors( + FlutterErrorDetails details, { + bool forceReport = false, +}) { + bool ifIsOverflowError = false; + bool isUnableToLoadAsset = false; + + // Detect overflow error. + var exception = details.exception; + if (exception is FlutterError) { + ifIsOverflowError = !exception.diagnostics.any( + (e) => e.value.toString().startsWith("A RenderFlex overflowed by"), + ); + isUnableToLoadAsset = !exception.diagnostics.any( + (e) => e.value.toString().startsWith("Unable to load asset"), + ); + } + + // Ignore if is overflow error. + if (ifIsOverflowError || isUnableToLoadAsset) { + debugPrint('Ignored Error'); + } else { + FlutterError.dumpErrorToConsole(details, forceReport: forceReport); + } +} diff --git a/clone-instagram-login-Refactoring/test/search_page_test.dart b/clone-instagram-login-Refactoring/test/search_page_test.dart new file mode 100644 index 0000000..7be9110 --- /dev/null +++ b/clone-instagram-login-Refactoring/test/search_page_test.dart @@ -0,0 +1,326 @@ +import 'package:example_widget_testing/app/modules/search/search_page.dart'; +import 'package:example_widget_testing/app/widgets/post_thumbnail.dart'; +import 'package:example_widget_testing/core/theme/colors.dart'; +import 'package:example_widget_testing/core/values/constant/search_json.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network_image_mock/network_image_mock.dart'; + +import 'helper.dart'; + +void checkError(int index, dynamic expected, dynamic matcher) { + try { + expect(expected, matcher); + } catch (e) { + debugPrint('Searchpage Test-$index failed:'); + debugPrint(e.toString()); + } +} + +void main() { + testWidgets('Check if Search page is present', (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: SearchPage(searchPosts: searchImages), + ), + ), + ); + + final searchPageListviewFinder = find.byKey( + const Key('search_page_listview'), + ); + checkError( + 1, + searchPageListviewFinder, + findsOneWidget, + ); + }); + + testWidgets('Check if search textfield is present', + (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: SearchPage(searchPosts: searchImages), + ), + ), + ); + + final searchPageListviewFinder = find.byKey( + const Key('search_page_listview'), + ); + + final searchPageTextfieldContainerFinder = find.byKey( + const Key('search_page_textfield_container'), + ); + // mock screen size + tester.binding.window.physicalSizeTestValue = const Size(375, 812); + checkError( + 2, + find.descendant( + of: searchPageListviewFinder, + matching: searchPageTextfieldContainerFinder, + ), + findsOneWidget); + final searchPageTextfieldContainer = searchPageTextfieldContainerFinder + .evaluate() + .single + .widget as Container; + + checkError( + 3, + searchPageTextfieldContainer.margin, + const EdgeInsets.only( + bottom: 15, + left: 15, + right: 15, + ), + ); + + checkError(4, searchPageTextfieldContainer.constraints!.maxHeight, 45.0); + checkError( + 5, + searchPageTextfieldContainer.decoration, + isA(), + ); + + final searchPageTextfieldContainerDecoration = + searchPageTextfieldContainer.decoration as BoxDecoration; + checkError( + 6, + searchPageTextfieldContainerDecoration.borderRadius, + const BorderRadius.all(Radius.circular(10)), + ); + checkError( + 7, + searchPageTextfieldContainerDecoration.color, + const Color(0xff262626), + ); + + final searchPageTextfieldFinder = find.byKey( + const Key('search_page_textfield'), + ); + checkError( + 8, + find.descendant( + of: searchPageListviewFinder, + matching: searchPageTextfieldFinder, + ), + findsOneWidget, + ); + + final searchPageTextfield = + searchPageTextfieldFinder.evaluate().single.widget as TextField; + checkError(9, searchPageTextfield.cursorColor, white.withOpacity(0.3)); + checkError(10, searchPageTextfield.style, isA()); + + final searchPageTextfieldStyle = searchPageTextfield.style as TextStyle; + checkError(11, searchPageTextfieldStyle.color, white.withOpacity(0.3)); + + checkError(12, searchPageTextfield.decoration, isA()); + + final searchPageTextfieldDecoration = + searchPageTextfield.decoration as InputDecoration; + checkError(13, searchPageTextfieldDecoration.border, InputBorder.none); + checkError(14, searchPageTextfieldDecoration.prefixIcon, isA()); + + final searchPageTextfieldPrefixIcon = + searchPageTextfieldDecoration.prefixIcon as Icon; + checkError(15, searchPageTextfieldPrefixIcon.icon, Icons.search); + checkError(16, searchPageTextfieldPrefixIcon.color, white.withOpacity(0.3)); + + final searchPageWrapFinder = find.byKey( + const Key('search_page_wrap'), + ); + checkError( + 17, + find.descendant( + of: searchPageListviewFinder, + matching: searchPageWrapFinder, + ), + findsOneWidget, + ); + + final searchPageWrap = + searchPageWrapFinder.evaluate().single.widget as Wrap; + checkError(18, searchPageWrap.spacing, 1); + checkError(19, searchPageWrap.runSpacing, 1); + checkError(20, searchPageWrap.children.length, searchImages.length); + }); + + testWidgets('Check if search posts is present', (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: SearchPage(searchPosts: searchImages), + ), + ), + ); + + final searchPageListviewFinder = find.byKey( + const Key('search_page_listview'), + ); + final searchPageWrapFinder = find.byKey( + const Key('search_page_wrap'), + ); + checkError( + 21, + find.descendant( + of: searchPageListviewFinder, + matching: searchPageWrapFinder, + ), + findsOneWidget, + ); + checkError( + 22, + find.descendant( + of: searchPageWrapFinder, + matching: find.byType(Container), + ), + findsNWidgets(searchImages.length), + ); + }); + + testWidgets('Check if search posts thumbnail is present', + (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + const String imageUrl = "https://picsum.photos/250?image=9"; + // mock screen size + tester.binding.window.physicalSizeTestValue = const Size(375, 812); + await mockNetworkImagesFor( + () => tester.pumpWidget( + const MaterialApp( + home: PostThumbnail(imageUrl: imageUrl), + ), + ), + ); + + final postThumbnailContainerFinder = find.byKey( + const Key(imageUrl), + ); + checkError(23, postThumbnailContainerFinder, findsOneWidget); + + final postThumbnailContainer = + postThumbnailContainerFinder.evaluate().single.widget as Container; + checkError(24, postThumbnailContainer.decoration, isA()); + + final postThumbnailContainerDecoration = + postThumbnailContainer.decoration as BoxDecoration; + checkError( + 25, + postThumbnailContainerDecoration.image, + isA(), + ); + + final postThumbnailContainerDecorationImage = + postThumbnailContainerDecoration.image as DecorationImage; + checkError( + 26, + postThumbnailContainerDecorationImage.image, + isA(), + ); + checkError( + 27, + postThumbnailContainerDecorationImage.fit, + BoxFit.cover, + ); + + final postThumbnailContainerDecorationImageNetworkImage = + postThumbnailContainerDecorationImage.image as NetworkImage; + checkError( + 28, + postThumbnailContainerDecorationImageNetworkImage.url, + imageUrl, + ); + }); + + testWidgets('Check if Bottom Navbar is present', (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: SearchPage(searchPosts: searchImages), + ), + ), + ); + + int pageIndex = 1; + + final bottomItem2Finder = find.byKey( + const Key('bottom_item_1'), + ); + checkError(29, bottomItem2Finder, findsOneWidget); + + await tester.ensureVisible(bottomItem2Finder); + await tester.pumpAndSettle(); + await tester.tap(bottomItem2Finder); + + List bottomItems = [ + pageIndex == 0 + ? "assets/images/home_active_icon.svg" + : "assets/images/home_icon.svg", + pageIndex == 1 + ? "assets/images/search_active_icon.svg" + : "assets/images/search_icon.svg", + pageIndex == 2 + ? "assets/images/upload_active_icon.svg" + : "assets/images/upload_icon.svg", + pageIndex == 3 + ? "assets/images/love_active_icon.svg" + : "assets/images/love_icon.svg", + pageIndex == 4 + ? "assets/images/account_active_icon.svg" + : "assets/images/account_icon.svg", + ]; + + final bottomNavigationBarContainer = + find.byKey(const Key('bottom_navigation_bar_container')); + checkError(188, bottomNavigationBarContainer, findsOneWidget); + + final bottomNavigationBarContainerFinder = + bottomNavigationBarContainer.evaluate().first.widget as Container; + checkError( + 189, bottomNavigationBarContainerFinder.constraints!.maxHeight, 55); + checkError(190, bottomNavigationBarContainerFinder.constraints!.maxWidth, + double.infinity); + checkError(191, bottomNavigationBarContainerFinder.color, black); + checkError(192, bottomNavigationBarContainerFinder.padding, + const EdgeInsets.only(left: 20, right: 20, bottom: 20, top: 15)); + + final bottomNavigationBarRowFinder = + find.byKey(const Key('bottom_navigation_bar_row')); + checkError( + 193, + find.descendant( + of: bottomNavigationBarContainer, + matching: bottomNavigationBarRowFinder), + findsOneWidget); + + final bottomNavigationBarRow = + bottomNavigationBarRowFinder.evaluate().first.widget as Row; + checkError(194, bottomNavigationBarRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween); + checkError(195, bottomNavigationBarRow.children, hasLength(5)); + + bottomItems.asMap().forEach((index, value) { + final bottomItem = bottomNavigationBarRow.children[index] as InkWell; + checkError(196, bottomItem.onTap, isA()); + checkError(197, bottomItem.child, isA()); + + final bottomItemSvgPicture = bottomItem.child as SvgPicture; + checkError(198, bottomItemSvgPicture.pictureProvider.runtimeType, + ExactAssetPicture); + checkError(199, bottomItemSvgPicture.width, 27); + final bottomItemSvgPicturePictureProvider = + bottomItemSvgPicture.pictureProvider as ExactAssetPicture; + checkError(200, bottomItemSvgPicturePictureProvider.assetName, + bottomItems[index]); + }); + }); +} diff --git a/clone-instagram-login-Refactoring/test/task_2_test.dart b/clone-instagram-login-Refactoring/test/task_2_test.dart new file mode 100644 index 0000000..40fdbe4 --- /dev/null +++ b/clone-instagram-login-Refactoring/test/task_2_test.dart @@ -0,0 +1,358 @@ +import 'package:example_widget_testing/app/modules/login/login_page.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'test_library.dart'; + +const List languages = [ + 'English', + 'Arabic', + 'Italian', + 'French' +]; + +void main() { + final states = {}; + + testWidgets('Check if language dropdown is present', (tester) async { + FlutterError.onError = customFlutterErrorHandler; + await tester.pumpWidget(const MaterialApp(home: LoginPage())); + final dropdownButtonFinder = find.byType(DropdownButton); + final dropdownButton = + dropdownButtonFinder.evaluate().first.widget as DropdownButton; + + checkByTypeFindOneWidget(dropdownButtonFinder); + checkWidgetProperty( + "dropdownColor", + dropdownButtonFinder, + dropdownButton.dropdownColor, + Colors.white, + ); + + checkWidgetProperty( + "color", + dropdownButtonFinder, + dropdownButton.style!.color, + Colors.black54, + ); + checkWidgetProperty( + "elevation", + dropdownButtonFinder, + dropdownButton.elevation, + 10, + ); + for (var language in languages) { + checkWidgetProperty( + "Text.data", + dropdownButtonFinder, + (dropdownButton.items! + .where((item) => item.value == language) + .first + .child as Text) + .data, + language, + ); + } + for (var language in languages) { + checkWidgetProperty( + "fontSize", + dropdownButtonFinder, + (dropdownButton.items! + .where((item) => item.value == language) + .first + .child as Text) + .style! + .fontSize, + 16, + ); + } + }); + + testWidgets('Check if username textbox is present', (tester) async { + FlutterError.onError = customFlutterErrorHandler; + tester.binding.window.physicalSizeTestValue = const Size(360, 640); + addTearDown(tester.binding.window.clearPhysicalSizeTestValue); + + await tester.pumpWidget(const MaterialApp(home: LoginPage())); + final usernameTextboxFinder = find.byKey(const Key('username_textfield')); + + final usernameTextbox = + usernameTextboxFinder.evaluate().first.widget as TextField; + checkByKeyFindOneWidget(usernameTextboxFinder); + checkWidgetProperty( + "hintText", + usernameTextboxFinder, + usernameTextbox.decoration!.hintText, + 'Phone number , email or username', + ); + checkWidgetProperty( + "fontSize", + usernameTextboxFinder, + usernameTextbox.style!.fontSize, + 15, + ); + }); + + testWidgets('Check if password textbox is present', (tester) async { + FlutterError.onError = customFlutterErrorHandler; + tester.binding.window.physicalSizeTestValue = const Size(360, 640); + addTearDown(tester.binding.window.clearPhysicalSizeTestValue); + + await tester.pumpWidget(const MaterialApp(home: LoginPage())); + + final passwordTextboxFinder = find.byKey(const Key('password_textfield')); + checkByKeyFindOneWidget(passwordTextboxFinder); + + final passwordTextbox = + passwordTextboxFinder.evaluate().first.widget as TextField; + checkWidgetProperty( + "hintText", + passwordTextboxFinder, + passwordTextbox.decoration!.hintText, + 'Password', + ); + + await tester.enterText(passwordTextboxFinder, 'password'); + checkWidgetProperty( + "obscureText", + passwordTextboxFinder, + passwordTextbox.obscureText, + true, + ); + }); + + testWidgets('Check if login button is present', (tester) async { + FlutterError.onError = customFlutterErrorHandler; + await tester.pumpWidget(const MaterialApp(home: LoginPage())); + + final loginButtonFinder = find.byKey( + const Key('login_button_elevated_button'), + ); + + final loginButton = + loginButtonFinder.evaluate().first.widget as ElevatedButton; + checkByKeyFindOneWidget(loginButtonFinder); + checkWidgetProperty( + "backgroundColor", + loginButtonFinder, + loginButton.style!.backgroundColor!.resolve(states), + const Color(0xff78c9ff), + ); + }); + + testWidgets('Check Forgot Login Text', (tester) async { + FlutterError.onError = customFlutterErrorHandler; + await tester.pumpWidget(const MaterialApp(home: LoginPage())); + + final forgotAccessFinder = find.byKey(const Key('forgot_access_text')); + checkByKeyFindOneWidget(forgotAccessFinder); + + final forgotAccessText = forgotAccessFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "Text.data", + forgotAccessFinder, + forgotAccessText.data, + 'Forgot your login details? ', + ); + checkWidgetProperty( + "fontSize", + forgotAccessFinder, + forgotAccessText.style!.fontSize, + 13, + ); + checkWidgetProperty( + "color", + forgotAccessFinder, + forgotAccessText.style!.color, + Colors.black, + ); + checkWidgetProperty( + "fontWeight", + forgotAccessFinder, + forgotAccessText.style!.fontWeight, + FontWeight.normal, + ); + }); + + testWidgets('Check if Get Help text is present', (tester) async { + FlutterError.onError = customFlutterErrorHandler; + + await tester.pumpWidget(const MaterialApp(home: LoginPage())); + + final getHelpFinder = find.byKey(const Key('get_help_text')); + checkByKeyFindOneWidget(getHelpFinder); + + final getHelpText = getHelpFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "Text.data", + getHelpFinder, + getHelpText.data, + 'Get help', + ); + checkWidgetProperty( + "fontSize", + getHelpFinder, + getHelpText.style!.fontSize, + 13, + ); + checkWidgetProperty( + "color", + getHelpFinder, + getHelpText.style!.color, + const Color(0xff002588), + ); + checkWidgetProperty( + "fontWeight", + getHelpFinder, + getHelpText.style!.fontWeight, + FontWeight.bold, + ); + }); + + testWidgets('Check if Facebook login is present', (tester) async { + FlutterError.onError = customFlutterErrorHandler; + + await tester.pumpWidget(const MaterialApp(home: LoginPage())); + + final facebookLoginFinder = find.byKey(const Key('facebook_login')); + checkByKeyFindOneWidget(facebookLoginFinder); + + final facebookLogo = find.byKey(const Key('facebook_logo')); + checkByKeyFindOneWidget(facebookLogo); + + final facebookTextFinder = find.byKey(const Key('facebook_login_text')); + checkByKeyFindOneWidget(facebookTextFinder); + + final facebookText = facebookTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "Text.data", + facebookTextFinder, + facebookText.data, + 'Login with facebook', + ); + checkWidgetProperty( + "color", + facebookTextFinder, + facebookText.style!.color, + const Color(0xff1877f2), + ); + checkWidgetProperty( + "fontWeight", + facebookTextFinder, + facebookText.style!.fontWeight, + FontWeight.w800, + ); + }); + + testWidgets('Check if signup text is present', (tester) async { + FlutterError.onError = customFlutterErrorHandler; + + await tester.pumpWidget(const MaterialApp(home: LoginPage())); + + final signupSectionFinder = find.byKey(const Key('signup_section')); + checkByKeyFindOneWidget(signupSectionFinder); + + final signupSection = signupSectionFinder.evaluate().first.widget as Row; + checkWidgetProperty( + "mainAxisAlignment", + signupSectionFinder, + signupSection.mainAxisAlignment, + MainAxisAlignment.center, + ); + + final signupText = signupSection.children[0] as Text; + checkWidgetProperty( + "Text.data", + signupSectionFinder.first, + signupText.data, + "Don't have an account? ", + ); + + checkWidgetProperty( + "fontSize", + signupSectionFinder, + signupText.style!.fontSize, + tester.binding.window.physicalSize.width * .040 / 3, + ); + + final signupButton = signupSection.children[1] as TextButton; + final signupButtonText = signupButton.child as Text; + checkWidgetProperty( + "Text.data", + signupSectionFinder, + signupButtonText.data, + 'Sign up', + ); + checkWidgetProperty( + "color", + signupSectionFinder, + signupButtonText.style!.color, + const Color(0xff00258B), + ); + checkWidgetProperty( + "fontWeight", + signupSectionFinder, + signupButtonText.style!.fontWeight, + FontWeight.bold, + ); + checkWidgetProperty( + "fontSize", + signupSectionFinder, + signupButtonText.style!.fontSize, + tester.binding.window.physicalSize.width * .040 / 3, + ); + }); + + // test if login button is disabled when username and password are empty + testWidgets( + 'Check if login button is disabled when username and password are empty', + (tester) async { + FlutterError.onError = customFlutterErrorHandler; + await tester.pumpWidget(const MaterialApp(home: LoginPage())); + + final loginButtonFinder = find.byKey( + const Key('login_button_elevated_button'), + ); + + final loginButton = + loginButtonFinder.evaluate().first.widget as ElevatedButton; + checkByKeyFindOneWidget(loginButtonFinder); + checkWidgetProperty( + "backgroundColor", + loginButtonFinder, + loginButton.style!.backgroundColor!.resolve(states), + const Color(0xff78c9ff), + ); + }); + + // test if login button is enabled when username and password are not empty + // testWidgets( + // "Check if login button is enabled when username and password are filled", + // (tester) async { + // FlutterError.onError = customFlutterErrorHandler; + // await tester.pumpWidget(const MaterialApp(home: LoginPage())); + + // final loginButtonFinder = find.byKey( + // const Key('login_button_elevated_button'), + // ); + + // // find username textbox + // final usernameTextboxFinder = find.byKey(const Key('username_textfield')); + // // find password textbox + // final passwordTextboxFinder = find.byKey(const Key('password_textfield')); + + // // enter username + // await tester.enterText(usernameTextboxFinder, 'username'); + // // enter password + // await tester.enterText(passwordTextboxFinder, 'password'); + + // final loginButton = + // loginButtonFinder.evaluate().first.widget as ElevatedButton; + // checkByKeyFindOneWidget(loginButtonFinder); + // checkWidgetProperty( + // "backgroundColor", + // loginButtonFinder, + // loginButton.style!.backgroundColor!.resolve(states), + // const Color(0xff26A9FF), + // ); + // }); +} diff --git a/clone-instagram-login-Refactoring/test/task_3_test.dart b/clone-instagram-login-Refactoring/test/task_3_test.dart new file mode 100644 index 0000000..8330c93 --- /dev/null +++ b/clone-instagram-login-Refactoring/test/task_3_test.dart @@ -0,0 +1,348 @@ +import 'package:example_widget_testing/app/modules/activity/activity_page.dart'; +import 'package:example_widget_testing/app/modules/home/components/story_item.dart'; +import 'package:example_widget_testing/app/modules/home/home_page.dart'; +import 'package:example_widget_testing/app/modules/login/login_page.dart'; +import 'package:example_widget_testing/core/values/constant/profile_json.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network_image_mock/network_image_mock.dart'; +import 'package:example_widget_testing/core/values/constant/story_json.dart'; +import 'package:example_widget_testing/core/theme/colors.dart'; +import 'package:example_widget_testing/core/values/constant/post_json.dart'; +import 'test_library.dart'; + +void main() { + testWidgets('Check if previous task 2 is finished', + (WidgetTester tester) async { + FlutterError.onError = unfinishedTaskErrorHandler; + await mockNetworkImagesFor( + () => tester.pumpWidget( + const MaterialApp( + home: LoginPage(), + ), + ), + ); + final loginPageFinder = find.byType(LoginPage); + checkByTypeFindOneWidget(loginPageFinder); + }); + + testWidgets('Check if home page is present', (WidgetTester tester) async { + FlutterError.onError = customFlutterErrorHandler; + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: HomePage( + posts: posts, + profileData: profileJson, + stories: stories, + ), + ), + ), + ); + final homePageFinder = find.byType(HomePage); + checkByTypeFindOneWidget(homePageFinder); + }); + + testWidgets('Check if Home page Appbar is present', + (WidgetTester tester) async { + FlutterError.onError = customFlutterErrorHandler; + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: HomePage( + posts: posts, profileData: profileJson, stories: stories), + ), + ), + ); + + final appBarFinder = find.byKey(const Key('home_page_appbar')); + checkByKeyFindOneWidget(appBarFinder); + + final appBar = appBarFinder.evaluate().first.widget as AppBar; + checkWidgetProperty( + "backgroundColor", appBar, appBar.backgroundColor, Colors.black); + checkByKeyIsWidget(appBar.leading, isA()); + + final appBarLeading = appBar.leading as Icon; + checkWidgetProperty("icon", appBar, appBarLeading.icon, Icons.camera_alt); + checkByKeyIsWidget(appBar.title, isA
()); + + final appBarTitle = appBar.title as Center; + checkByKeyIsWidget(appBarTitle.child, isA()); + checkByKeyIsWidget(appBar.actions, isA>()); + // checkError(9, appBar.actions?.length, 1); + + final appBarAction = appBar.actions?.first as Icon; + checkWidgetProperty("icon", appBar, appBarAction.icon, Icons.send); + }); + + testWidgets('Check if Story is present', (WidgetTester tester) async { + FlutterError.onError = customFlutterErrorHandler; + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: HomePage( + posts: posts, + profileData: profileJson, + stories: stories, + ), + ), + ), + ); + + final storyFinder = find.byKey(const Key('following_stories_row')); + checkByKeyFindOneWidget(storyFinder); + + final story = storyFinder.evaluate().first.widget as Row; + checkByKeyIsWidget(story.children, isA>()); + checkWidgetProperty( + "length", storyFinder, story.children.length, stories.length); + checkByKeyIsWidget(story.children[0], isA()); + + stories.asMap().forEach((index, value) { + final storyItem = story.children[index] as StoryItem; + checkWidgetProperty("name", storyFinder, storyItem.name, value['name']); + checkWidgetProperty("img", storyFinder, storyItem.img, value['img']); + }); + }); + + testWidgets('Check if StoryItem rendered correctly', + (WidgetTester tester) async { + // Define test data + const String imageUrl = 'https://example.com/image.jpg'; + const String name = 'John Doe'; + + FlutterError.onError = customFlutterErrorHandler; + + await mockNetworkImagesFor(() => tester.pumpWidget( + const MaterialApp(home: StoryItem(img: imageUrl, name: name)))); + + // checkError(17, find.byType(Container), findsNWidgets(2)); + + final storyItemPaddingFinder = find.byKey(const Key('story_item_padding')); + checkByKeyFindOneWidget(storyItemPaddingFinder); + + final storyItemPadding = + storyItemPaddingFinder.evaluate().first.widget as Padding; + checkWidgetProperty( + "padding", + storyItemPaddingFinder, + storyItemPadding.padding, + const EdgeInsets.only(right: 20, bottom: 10), + ); + + final storyItemColumnFinder = find.byKey(const Key('story_item_column')); + checkByKeyFindOneWidget(storyItemColumnFinder); + checkWidgetDescendantProperty( + storyItemPaddingFinder, storyItemColumnFinder); + + final storyItemColumn = + storyItemColumnFinder.evaluate().first.widget as Column; + checkByKeyIsWidget(storyItemColumn.children, isA>()); + // checkError(23, storyItemColumn.children.length, 2); + + final storyItemContainerFinder = find.byKey( + const Key('story_item_container'), + ); + checkWidgetDescendantProperty( + storyItemColumnFinder, storyItemContainerFinder); + + final storyItemContainer = + storyItemContainerFinder.evaluate().first.widget as Container; + + checkWidgetProperty( + "width", + storyItemContainerFinder, + storyItemContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 68, maxWidth: 68), + ); + + checkWidgetProperty( + "margin", + storyItemContainerFinder, + storyItemContainer.margin, + const EdgeInsets.only(bottom: 8), + ); + + checkWidgetProperty( + "height", + storyItemContainerFinder, + storyItemContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 68, maxHeight: 68), + ); + + checkByKeyIsWidget(storyItemContainer.decoration, isA()); + + final storyItemContainerDecoration = + storyItemContainer.decoration as BoxDecoration; + checkWidgetProperty( + "shape", + storyItemContainerFinder, + storyItemContainerDecoration.shape, + BoxShape.circle, + ); + + checkByKeyIsWidget( + storyItemContainerDecoration.gradient, isA()); + final storyItemContainerGradient = + storyItemContainerDecoration.gradient as LinearGradient; + checkWidgetProperty( + "begin", + storyItemContainerFinder, + storyItemContainerGradient.begin, + Alignment.topCenter, + ); + checkWidgetProperty( + 'end', + storyItemContainerFinder, + storyItemContainerGradient.end, + Alignment.bottomCenter, + ); + checkWidgetProperty( + "colors", + storyItemContainerFinder, + storyItemContainerGradient.colors, + const [Color(0xFF9B2282), Color(0xFFEEA863)], + ); + + final storyItemImageContainerFinder = find.byKey( + const Key('story_item_image_container'), + ); + + checkWidgetDescendantProperty( + storyItemContainerFinder, storyItemImageContainerFinder); + + final storyItemImageContainer = + storyItemImageContainerFinder.evaluate().first.widget as Container; + + checkWidgetProperty( + "width", + storyItemImageContainerFinder, + storyItemImageContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 65, maxWidth: 65), + ); + + checkWidgetProperty( + "height", + storyItemImageContainerFinder, + storyItemImageContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 65, maxHeight: 65), + ); + + checkWidgetProperty( + "margin", + storyItemImageContainerFinder, + storyItemImageContainer.margin, + const EdgeInsets.all(3), + ); + + checkByKeyIsWidget( + storyItemImageContainer.decoration, isA()); + + final storyItemImageContainerDecoration = + storyItemImageContainer.decoration as BoxDecoration; + checkWidgetProperty( + "shape", + storyItemImageContainerFinder, + storyItemImageContainerDecoration.shape, + BoxShape.circle, + ); + checkWidgetProperty( + "border", + storyItemImageContainerFinder, + storyItemImageContainerDecoration.border, + const Border.fromBorderSide( + BorderSide( + color: black, + width: 2, + style: BorderStyle.solid, + ), + ), + ); + + checkByKeyIsWidget( + storyItemImageContainerDecoration.image, isA()); + + final storyItemImageContainerDecorationImage = + (storyItemImageContainer.decoration as BoxDecoration).image + as DecorationImage; + checkByKeyIsWidget( + storyItemImageContainerDecorationImage.image, isA()); + + checkWidgetProperty( + "fit", + storyItemImageContainerFinder, + storyItemImageContainerDecorationImage.fit, + BoxFit.cover, + ); + + final storyItemUsernameSizeBoxFinder = find.byKey( + const Key('story_item_username_sizedbox'), + ); + + checkWidgetDescendantProperty( + storyItemColumnFinder, storyItemUsernameSizeBoxFinder); + + final storyItemUsernameSizeBox = + storyItemUsernameSizeBoxFinder.evaluate().first.widget as SizedBox; + checkWidgetProperty( + "width", + storyItemUsernameSizeBoxFinder, + storyItemUsernameSizeBox.width, + 70, + ); + + final storyItemUsernameTextFinder = find.byKey( + const Key('story_item_username_text'), + ); + + checkWidgetDescendantProperty( + storyItemUsernameSizeBoxFinder, storyItemUsernameTextFinder); + + final storyItemUsernameText = + storyItemUsernameTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "data", + storyItemUsernameTextFinder, + storyItemUsernameText.data, + name, + ); + checkWidgetProperty( + "overflow", + storyItemUsernameTextFinder, + storyItemUsernameText.overflow, + TextOverflow.ellipsis, + ); + checkWidgetProperty( + "color", + storyItemUsernameTextFinder, + storyItemUsernameText.style!.color, + white, + ); + }); + + testWidgets('Check if divider is present', (WidgetTester tester) async { + FlutterError.onError = customFlutterErrorHandler; + + await tester.pumpWidget( + MaterialApp( + home: HomePage( + posts: posts, + profileData: profileJson, + stories: stories, + ), + ), + ); + + final dividerFinder = find.byKey(const Key('home_page_divider')); + checkByKeyFindOneWidget(dividerFinder); + + final divider = dividerFinder.evaluate().first.widget as Divider; + checkWidgetProperty( + "color", + dividerFinder, + divider.color, + white.withOpacity(0.3), + ); + }); +} diff --git a/clone-instagram-login-Refactoring/test/task_4_test.dart b/clone-instagram-login-Refactoring/test/task_4_test.dart new file mode 100644 index 0000000..defa422 --- /dev/null +++ b/clone-instagram-login-Refactoring/test/task_4_test.dart @@ -0,0 +1,1199 @@ +import 'package:example_widget_testing/app/modules/home/components/story_item.dart'; +import 'package:example_widget_testing/app/modules/home/home_page.dart'; +import 'package:example_widget_testing/app/modules/login/login_page.dart'; +import 'package:example_widget_testing/app/widgets/post_item.dart'; +import 'package:example_widget_testing/core/theme/colors.dart'; +import 'package:example_widget_testing/core/values/constant/post_json.dart'; +import 'package:example_widget_testing/core/values/constant/profile_json.dart'; +import 'package:example_widget_testing/core/values/constant/story_json.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network_image_mock/network_image_mock.dart'; + +import 'test_library.dart'; + +void main() { + testWidgets('Check if Task 2 is finished', (WidgetTester tester) async { + FlutterError.onError = unfinishedTaskErrorHandler; + await mockNetworkImagesFor( + () => tester.pumpWidget( + const MaterialApp( + home: LoginPage(), + ), + ), + ); + final loginPageFinder = find.byType(LoginPage); + checkByTypeFindOneWidget(loginPageFinder); + }); + + testWidgets('Check if Task 3 is finished', (WidgetTester tester) async { + FlutterError.onError = unfinishedTaskErrorHandler; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: HomePage( + posts: posts, + profileData: profileJson, + stories: stories, + ), + ), + ), + ); + final homePageFinder = find.byType(HomePage); + checkByTypeFindOneWidget(homePageFinder); + + final appBarFinder = find.byKey(const Key('home_page_appbar')); + checkByKeyFindOneWidget(appBarFinder); + + final appBar = appBarFinder.evaluate().first.widget as AppBar; + checkWidgetProperty( + "backgroundColor", appBar, appBar.backgroundColor, Colors.black); + checkByKeyIsWidget(appBar.leading, isA()); + + final appBarLeading = appBar.leading as Icon; + checkWidgetProperty("icon", appBar, appBarLeading.icon, Icons.camera_alt); + checkByKeyIsWidget(appBar.title, isA
()); + + final appBarTitle = appBar.title as Center; + checkByKeyIsWidget(appBarTitle.child, isA()); + checkByKeyIsWidget(appBar.actions, isA>()); + // checkError(9, appBar.actions?.length, 1); + + final appBarAction = appBar.actions?.first as Icon; + checkWidgetProperty("icon", appBar, appBarAction.icon, Icons.send); + + final storyFinder = find.byKey(const Key('following_stories_row')); + checkByKeyFindOneWidget(storyFinder); + + final story = storyFinder.evaluate().first.widget as Row; + checkByKeyIsWidget(story.children, isA>()); + checkWidgetProperty( + "length", storyFinder, story.children.length, stories.length); + checkByKeyIsWidget(story.children[0], isA()); + + stories.asMap().forEach((index, value) { + final storyItem = story.children[index] as StoryItem; + checkWidgetProperty("name", storyFinder, storyItem.name, value['name']); + checkWidgetProperty("img", storyFinder, storyItem.img, value['img']); + }); + + const String imageUrl = 'https://example.com/image.jpg'; + const String name = 'John Doe'; + + FlutterError.onError = customFlutterErrorHandler; + + await mockNetworkImagesFor(() => tester.pumpWidget( + const MaterialApp(home: StoryItem(img: imageUrl, name: name)))); + + // checkError(17, find.byType(Container), findsNWidgets(2)); + + final storyItemPaddingFinder = find.byKey(const Key('story_item_padding')); + checkByKeyFindOneWidget(storyItemPaddingFinder); + + final storyItemPadding = + storyItemPaddingFinder.evaluate().first.widget as Padding; + checkWidgetProperty( + "padding", + storyItemPaddingFinder, + storyItemPadding.padding, + const EdgeInsets.only(right: 20, bottom: 10), + ); + + final storyItemColumnFinder = find.byKey(const Key('story_item_column')); + checkByKeyFindOneWidget(storyItemColumnFinder); + checkWidgetDescendantProperty( + storyItemPaddingFinder, storyItemColumnFinder); + + final storyItemColumn = + storyItemColumnFinder.evaluate().first.widget as Column; + checkByKeyIsWidget(storyItemColumn.children, isA>()); + // checkError(23, storyItemColumn.children.length, 2); + + final storyItemContainerFinder = find.byKey( + const Key('story_item_container'), + ); + checkWidgetDescendantProperty( + storyItemColumnFinder, storyItemContainerFinder); + + final storyItemContainer = + storyItemContainerFinder.evaluate().first.widget as Container; + + checkWidgetProperty( + "width", + storyItemContainerFinder, + storyItemContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 68, maxWidth: 68), + ); + + checkWidgetProperty( + "margin", + storyItemContainerFinder, + storyItemContainer.margin, + const EdgeInsets.only(bottom: 8), + ); + + checkWidgetProperty( + "height", + storyItemContainerFinder, + storyItemContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 68, maxHeight: 68), + ); + + checkByKeyIsWidget(storyItemContainer.decoration, isA()); + + final storyItemContainerDecoration = + storyItemContainer.decoration as BoxDecoration; + checkWidgetProperty( + "shape", + storyItemContainerFinder, + storyItemContainerDecoration.shape, + BoxShape.circle, + ); + + checkByKeyIsWidget( + storyItemContainerDecoration.gradient, isA()); + final storyItemContainerGradient = + storyItemContainerDecoration.gradient as LinearGradient; + checkWidgetProperty( + "begin", + storyItemContainerFinder, + storyItemContainerGradient.begin, + Alignment.topCenter, + ); + checkWidgetProperty( + 'end', + storyItemContainerFinder, + storyItemContainerGradient.end, + Alignment.bottomCenter, + ); + checkWidgetProperty( + "colors", + storyItemContainerFinder, + storyItemContainerGradient.colors, + const [Color(0xFF9B2282), Color(0xFFEEA863)], + ); + + final storyItemImageContainerFinder = find.byKey( + const Key('story_item_image_container'), + ); + + checkWidgetDescendantProperty( + storyItemContainerFinder, storyItemImageContainerFinder); + + final storyItemImageContainer = + storyItemImageContainerFinder.evaluate().first.widget as Container; + + checkWidgetProperty( + "width", + storyItemImageContainerFinder, + storyItemImageContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 65, maxWidth: 65), + ); + + checkWidgetProperty( + "height", + storyItemImageContainerFinder, + storyItemImageContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 65, maxHeight: 65), + ); + + checkWidgetProperty( + "margin", + storyItemImageContainerFinder, + storyItemImageContainer.margin, + const EdgeInsets.all(3), + ); + + checkByKeyIsWidget( + storyItemImageContainer.decoration, isA()); + + final storyItemImageContainerDecoration = + storyItemImageContainer.decoration as BoxDecoration; + checkWidgetProperty( + "shape", + storyItemImageContainerFinder, + storyItemImageContainerDecoration.shape, + BoxShape.circle, + ); + checkWidgetProperty( + "border", + storyItemImageContainerFinder, + storyItemImageContainerDecoration.border, + const Border.fromBorderSide( + BorderSide( + color: black, + width: 2, + style: BorderStyle.solid, + ), + ), + ); + + checkByKeyIsWidget( + storyItemImageContainerDecoration.image, isA()); + + final storyItemImageContainerDecorationImage = + (storyItemImageContainer.decoration as BoxDecoration).image + as DecorationImage; + checkByKeyIsWidget( + storyItemImageContainerDecorationImage.image, isA()); + + checkWidgetProperty( + "fit", + storyItemImageContainerFinder, + storyItemImageContainerDecorationImage.fit, + BoxFit.cover, + ); + + final storyItemUsernameSizeBoxFinder = find.byKey( + const Key('story_item_username_sizedbox'), + ); + + checkWidgetDescendantProperty( + storyItemColumnFinder, storyItemUsernameSizeBoxFinder); + + final storyItemUsernameSizeBox = + storyItemUsernameSizeBoxFinder.evaluate().first.widget as SizedBox; + checkWidgetProperty( + "width", + storyItemUsernameSizeBoxFinder, + storyItemUsernameSizeBox.width, + 70, + ); + + final storyItemUsernameTextFinder = find.byKey( + const Key('story_item_username_text'), + ); + + checkWidgetDescendantProperty( + storyItemUsernameSizeBoxFinder, storyItemUsernameTextFinder); + + final storyItemUsernameText = + storyItemUsernameTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "data", + storyItemUsernameTextFinder, + storyItemUsernameText.data, + name, + ); + checkWidgetProperty( + "overflow", + storyItemUsernameTextFinder, + storyItemUsernameText.overflow, + TextOverflow.ellipsis, + ); + checkWidgetProperty( + "color", + storyItemUsernameTextFinder, + storyItemUsernameText.style!.color, + white, + ); + + await tester.pumpWidget( + MaterialApp( + home: HomePage( + posts: posts, + profileData: profileJson, + stories: stories, + ), + ), + ); + + final dividerFinder = find.byKey(const Key('home_page_divider')); + checkByKeyFindOneWidget(dividerFinder); + + final divider = dividerFinder.evaluate().first.widget as Divider; + checkWidgetProperty( + "color", + dividerFinder, + divider.color, + white.withOpacity(0.3), + ); + }); + + testWidgets('Check if Posts Column is present', (WidgetTester tester) async { + FlutterError.onError = customFlutterErrorHandler; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: HomePage( + posts: posts, + profileData: profileJson, + stories: stories, + ), + ), + ), + ); + + final homePageColumnFinder = find.byKey(const Key('home_page_column')); + final postsColumnFinder = find.byKey(const Key('posts_column')); + checkWidgetDescendantProperty(homePageColumnFinder, postsColumnFinder); + checkByKeyFindOneWidget(postsColumnFinder); + + final postsColumn = postsColumnFinder.evaluate().first.widget as Column; + checkError(53, postsColumn.children.length, posts.length); + }); + + testWidgets( + 'Check if PostItem rendered correctly', + (WidgetTester tester) async { + FlutterError.onError = customFlutterErrorHandler; + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: PostItem( + postImg: posts[0]['postImg'], + profileImg: posts[0]['profileImg'], + name: posts[0]['name'], + caption: posts[0]['caption'], + isLoved: posts[0]['isLoved'], + viewCount: posts[0]['commentCount'], + likedBy: posts[0]['likedBy'], + dayAgo: posts[0]['timeAgo'], + userPhoto: profile, + onPressed: () {}, + ), + ), + ), + ); + + final postItemPaddingFinder = find.byKey(const Key('post_item_padding')); + checkByKeyFindOneWidget(postItemPaddingFinder); + + final postItemPadding = + postItemPaddingFinder.evaluate().first.widget as Padding; + checkWidgetProperty( + "padding", + postItemPaddingFinder, + postItemPadding.padding, + const EdgeInsets.only(bottom: 10), + ); + + final postItemColumnFinder = find.byKey(const Key('post_item_column')); + checkWidgetDescendantProperty( + postItemPaddingFinder, postItemColumnFinder); + + final postItemColumn = + postItemColumnFinder.evaluate().first.widget as Column; + checkWidgetProperty( + "crossAxisAlignment", + postItemColumnFinder, + postItemColumn.crossAxisAlignment, + CrossAxisAlignment.start, + ); + // checkError(58, postItemColumn.children.length, 8); + + final postItemUserInfoContainerFinder = find.byKey( + const Key('post_item_user_info_container'), + ); + checkWidgetDescendantProperty( + postItemColumnFinder, postItemUserInfoContainerFinder); + + final postItemUserInfoContainer = + postItemUserInfoContainerFinder.evaluate().first.widget as Container; + checkWidgetProperty( + "padding", + postItemUserInfoContainerFinder, + postItemUserInfoContainer.padding, + const EdgeInsets.symmetric(vertical: 10, horizontal: 15), + ); + + checkWidgetProperty( + "margin", + postItemUserInfoContainerFinder, + postItemUserInfoContainer.margin, + const EdgeInsets.only(bottom: 12), + ); + + final postItemUserInfoRowFinder = find.byKey( + const Key('post_item_user_info_row'), + ); + checkWidgetDescendantProperty( + postItemUserInfoContainerFinder, postItemUserInfoRowFinder); + + final postItemUserInfoRow = + postItemUserInfoRowFinder.evaluate().first.widget as Row; + checkWidgetProperty( + "mainAxisAlignment", + postItemUserInfoRowFinder, + postItemUserInfoRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween, + ); + // checkError(64, postItemUserInfoRow.children.length, 3); + + final postItemUserImgContainerFinder = find.byKey( + const Key('post_item_user_profile_img_container'), + ); + checkWidgetDescendantProperty( + postItemUserInfoRowFinder, postItemUserImgContainerFinder); + + final postItemUserImgContainer = + postItemUserImgContainerFinder.evaluate().first.widget as Container; + checkWidgetProperty( + "width", + postItemUserImgContainerFinder, + postItemUserImgContainer.constraints!.maxWidth, + 40, + ); + checkWidgetProperty( + "height", + postItemUserImgContainerFinder, + postItemUserImgContainer.constraints!.maxHeight, + 40, + ); + checkWidgetProperty( + "margin", + postItemUserImgContainerFinder, + postItemUserImgContainer.margin, + const EdgeInsets.only(right: 15), + ); + checkByKeyIsWidget( + postItemUserImgContainer.decoration, isA()); + + final postItemUserImgContainerDecoration = + postItemUserImgContainer.decoration as BoxDecoration; + checkWidgetProperty( + "shape", + postItemUserImgContainerFinder, + postItemUserImgContainerDecoration.shape, + BoxShape.circle, + ); + checkByKeyIsWidget( + postItemUserImgContainerDecoration.image, + isA(), + ); + + final postItemUserImgContainerDecorationImage = + postItemUserImgContainerDecoration.image as DecorationImage; + checkByKeyIsWidget( + postItemUserImgContainerDecorationImage.image, isA()); + checkWidgetProperty( + "fit", + postItemUserImgContainerFinder, + postItemUserImgContainerDecorationImage.fit, + BoxFit.cover, + ); + + final postItemUserImgContainerDecorationImageNetworkImage = + postItemUserImgContainerDecorationImage.image as NetworkImage; + checkWidgetProperty( + "ImageNetworkImage.url", + postItemUserImgContainerFinder, + postItemUserImgContainerDecorationImageNetworkImage.url, + posts[0]['profileImg'], + ); + + final postItemUserNameExpendedFinder = find.byKey( + const Key('post_item_user_name_expanded'), + ); + checkWidgetDescendantProperty( + postItemUserInfoRowFinder, postItemUserNameExpendedFinder); + + final postItemUserNameTextFinder = find.byKey( + const Key('post_item_user_name_text'), + ); + checkWidgetDescendantProperty( + postItemUserNameExpendedFinder, postItemUserNameTextFinder); + + final postItemUserNameText = + postItemUserNameTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "data", + postItemUserNameTextFinder, + postItemUserNameText.data, + posts[0]['name'], + ); + checkByKeyIsWidget(postItemUserNameText.style, isA()); + + final postItemUserNameTextStyle = postItemUserNameText.style as TextStyle; + checkWidgetProperty( + "color", + postItemUserNameTextFinder, + postItemUserNameTextStyle.color, + Colors.white, + ); + checkWidgetProperty( + "fontWeight", + postItemUserNameTextFinder, + postItemUserNameTextStyle.fontWeight, + FontWeight.w500, + ); + checkWidgetProperty( + "fontSize", + postItemUserNameTextFinder, + postItemUserNameTextStyle.fontSize, + 15, + ); + + final postItemUserMoreIconFinder = find.byKey( + const Key('post_item_user_more_icon'), + ); + checkWidgetDescendantProperty( + postItemUserInfoRowFinder, postItemUserMoreIconFinder); + + final postItemUserMoreIcon = + postItemUserMoreIconFinder.evaluate().first.widget as Icon; + checkWidgetProperty( + "icon", + postItemUserMoreIconFinder, + postItemUserMoreIcon.icon, + Icons.more_horiz, + ); + checkWidgetProperty( + "color", + postItemUserMoreIconFinder, + postItemUserMoreIcon.color, + Colors.white, + ); + + final postItemImageContainerFinder = find.byKey( + const Key('post_item_image_container'), + ); + checkWidgetDescendantProperty( + postItemColumnFinder, postItemImageContainerFinder); + + final postItemImageContainer = + postItemImageContainerFinder.evaluate().first.widget as Container; + checkWidgetProperty( + "height", + postItemImageContainerFinder, + postItemImageContainer.constraints!.maxHeight, + 400, + ); + checkWidgetProperty( + "margin", + postItemImageContainerFinder, + postItemImageContainer.margin, + const EdgeInsets.only(bottom: 10), + ); + checkByKeyIsWidget( + postItemImageContainer.decoration, isA()); + + final postItemImageContainerDecoration = + postItemImageContainer.decoration as BoxDecoration; + checkByKeyIsWidget( + postItemImageContainerDecoration.image, isA()); + + final postItemImageContainerDecorationImage = + postItemImageContainerDecoration.image as DecorationImage; + checkByKeyIsWidget( + postItemImageContainerDecorationImage.image, isA()); + checkWidgetProperty( + "fit", + postItemImageContainerFinder, + postItemImageContainerDecorationImage.fit, + BoxFit.cover, + ); + + final postItemImageContainerDecorationImageNetworkImage = + postItemImageContainerDecorationImage.image as NetworkImage; + checkWidgetProperty( + "ImageNetworkImage.url", + postItemImageContainerFinder, + postItemImageContainerDecorationImageNetworkImage.url, + posts[0]['postImg'], + ); + + final postItemActionContainerFinder = + find.byKey(const Key('post_item_actions_container')); + checkWidgetDescendantProperty( + postItemColumnFinder, postItemActionContainerFinder); + + final postItemActionContainer = + postItemActionContainerFinder.evaluate().first.widget as Container; + checkWidgetProperty( + "padding", + postItemActionContainerFinder, + postItemActionContainer.padding, + const EdgeInsets.fromLTRB(15, 3, 15, 0), + ); + checkWidgetProperty( + "margin", + postItemActionContainerFinder, + postItemActionContainer.margin, + const EdgeInsets.only(bottom: 12), + ); + + final postItemActionRowFinder = find.byKey( + const Key('post_item_actions_row'), + ); + checkWidgetDescendantProperty( + postItemActionContainerFinder, + postItemActionRowFinder, + ); + + final postItemActionRow = + postItemActionRowFinder.evaluate().first.widget as Row; + checkWidgetProperty( + "mainAxisAlignment", + postItemActionRowFinder, + postItemActionRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween, + ); + // checkError(98, postItemActionRow.children.length, 2); + + final postItemActionsLeftRowFinder = find.byKey( + const Key('post_item_actions_left_row'), + ); + checkWidgetDescendantProperty( + postItemActionRowFinder, postItemActionsLeftRowFinder); + + // final postItemActionsLeftRow = + // postItemActionsLeftRowFinder.evaluate().first.widget as Row; + // checkError(100, postItemActionsLeftRow.children.length, 5); + + final postItemActionsLoveIconFinder = find.byKey( + const Key('post_item_actions_love_icon'), + ); + checkWidgetDescendantProperty( + postItemActionsLeftRowFinder, postItemActionsLoveIconFinder); + + final postItemActionsLoveIcon = + postItemActionsLoveIconFinder.evaluate().first.widget as SvgPicture; + checkByKeyIsWidget(postItemActionsLoveIcon, isA()); + checkWidgetProperty( + "width", + postItemActionsLoveIconFinder, + postItemActionsLoveIcon.width, + 27, + ); + checkWidgetProperty( + "pictureProvider.runtimeType", + postItemActionsLoveIconFinder, + postItemActionsLoveIcon.pictureProvider.runtimeType, + ExactAssetPicture, + ); + + final postItemActionsLoveIconPictureProvider = + postItemActionsLoveIcon.pictureProvider as ExactAssetPicture; + checkWidgetProperty( + "assetName", + postItemActionsLoveIconFinder, + postItemActionsLoveIconPictureProvider.assetName, + posts[0]['isLoved'] + ? 'assets/images/loved_icon.svg' + : 'assets/images/love_icon.svg', + ); + final postItemActionsLeftRowSizeBox1Finder = find.byKey( + const Key('post_item_actions_left_row_sized_box_1'), + ); + checkWidgetDescendantProperty( + postItemActionsLeftRowFinder, postItemActionsLeftRowSizeBox1Finder); + + final postItemActionsLeftRowSizeBox1 = + postItemActionsLeftRowSizeBox1Finder.evaluate().first.widget + as SizedBox; + checkWidgetProperty( + "width", + postItemActionsLeftRowSizeBox1Finder, + postItemActionsLeftRowSizeBox1.width, + 20, + ); + + final postItemActionsCommentIconFinder = find.byKey( + const Key('post_item_actions_comment_icon'), + ); + checkWidgetDescendantProperty( + postItemActionsLeftRowFinder, postItemActionsCommentIconFinder); + + final postItemActionsCommentIcon = postItemActionsCommentIconFinder + .evaluate() + .first + .widget as SvgPicture; + checkByKeyIsWidget(postItemActionsCommentIcon, isA()); + checkWidgetProperty( + "width", + postItemActionsCommentIconFinder, + postItemActionsCommentIcon.width, + 27, + ); + checkWidgetProperty( + "pictureProvider.runtimeType", + postItemActionsCommentIconFinder, + postItemActionsCommentIcon.pictureProvider.runtimeType, + ExactAssetPicture, + ); + + final postItemActionsCommentIconPictureProvider = + postItemActionsCommentIcon.pictureProvider as ExactAssetPicture; + checkWidgetProperty( + "assetName", + postItemActionsCommentIconFinder, + postItemActionsCommentIconPictureProvider.assetName, + "assets/images/comment_icon.svg", + ); + + final postItemActionsLeftRowSizeBox2Finder = find.byKey( + const Key('post_item_actions_left_row_sized_box_2'), + ); + checkWidgetDescendantProperty( + postItemActionsLeftRowFinder, postItemActionsLeftRowSizeBox2Finder); + + final postItemActionsLeftRowSizeBox2 = + postItemActionsLeftRowSizeBox2Finder.evaluate().first.widget + as SizedBox; + checkWidgetProperty( + "width", + postItemActionsLeftRowSizeBox2Finder, + postItemActionsLeftRowSizeBox2.width, + 20, + ); + + final postItemActionsMessageIconFinder = find.byKey( + const Key('post_item_actions_message_icon'), + ); + checkWidgetDescendantProperty( + postItemActionsLeftRowFinder, postItemActionsMessageIconFinder); + + final postItemActionsMessageIcon = postItemActionsMessageIconFinder + .evaluate() + .first + .widget as SvgPicture; + checkByKeyIsWidget(postItemActionsMessageIcon, isA()); + checkWidgetProperty( + "width", + postItemActionsMessageIconFinder, + postItemActionsMessageIcon.width, + 27, + ); + checkWidgetProperty( + "pictureProvider.runtimeType", + postItemActionsMessageIconFinder, + postItemActionsMessageIcon.pictureProvider.runtimeType, + ExactAssetPicture, + ); + + final postItemActionsMessageIconPictureProvider = + postItemActionsMessageIcon.pictureProvider as ExactAssetPicture; + checkWidgetProperty( + "assetName", + postItemActionsMessageIconFinder, + postItemActionsMessageIconPictureProvider.assetName, + "assets/images/message_icon.svg", + ); + + final postItemActionsSaveIconFinder = find.byKey( + const Key('post_item_actions_save_icon'), + ); + checkWidgetDescendantProperty( + postItemActionRowFinder, postItemActionsSaveIconFinder); + + final postItemActionsSaveIcon = + postItemActionsSaveIconFinder.evaluate().first.widget as SvgPicture; + checkByKeyIsWidget(postItemActionsSaveIcon, isA()); + checkWidgetProperty( + "width", + postItemActionsSaveIconFinder, + postItemActionsSaveIcon.width, + 27, + ); + checkWidgetProperty( + "pictureProvider.runtimeType", + postItemActionsSaveIconFinder, + postItemActionsSaveIcon.pictureProvider.runtimeType, + ExactAssetPicture); + + final postItemActionsSaveIconPictureProvider = + postItemActionsSaveIcon.pictureProvider as ExactAssetPicture; + checkWidgetProperty( + "assetName", + postItemActionsSaveIconFinder, + postItemActionsSaveIconPictureProvider.assetName, + "assets/images/save_icon.svg", + ); + + final postItemCaptionContainerFinder = find.byKey( + const Key('post_item_caption_container'), + ); + checkWidgetDescendantProperty( + postItemColumnFinder, + postItemCaptionContainerFinder, + ); + + final postItemCaptionContainer = + postItemCaptionContainerFinder.evaluate().first.widget as Container; + checkByKeyIsWidget(postItemCaptionContainer, isA()); + checkWidgetProperty( + "padding", + postItemCaptionContainerFinder, + postItemCaptionContainer.padding, + const EdgeInsets.symmetric(horizontal: 15), + ); + checkWidgetProperty( + "margin", + postItemCaptionContainerFinder, + postItemCaptionContainer.margin, + const EdgeInsets.only(bottom: 12), + ); + + final postItemCaptionRichTextFinder = find.byKey( + const Key('post_item_caption_rich_text'), + ); + checkWidgetDescendantProperty( + postItemCaptionContainerFinder, postItemCaptionRichTextFinder); + + final postItemCaptionRichText = + postItemCaptionRichTextFinder.evaluate().first.widget as RichText; + checkByKeyIsWidget(postItemCaptionRichText.text, isA()); + + final postItemCaptionRichTextTextSpan = + postItemCaptionRichText.text as TextSpan; + // checkError(131, postItemCaptionRichTextTextSpan.children, hasLength(2)); + + final postItemCaptionRichTextTextSpanTextSpan1 = + postItemCaptionRichTextTextSpan.children![0] as TextSpan; + checkWidgetProperty( + "text", + postItemCaptionRichTextTextSpanTextSpan1, + postItemCaptionRichTextTextSpanTextSpan1.text, + posts[0]['name'] + ' '); + checkWidgetProperty( + "text", + postItemCaptionRichTextTextSpanTextSpan1, + postItemCaptionRichTextTextSpanTextSpan1.style, + const TextStyle(fontSize: 15, fontWeight: FontWeight.w700), + ); + + final postItemCaptionRichTextTextSpanTextSpan2 = + postItemCaptionRichTextTextSpan.children![1] as TextSpan; + checkWidgetProperty("text", postItemCaptionRichTextTextSpanTextSpan2, + postItemCaptionRichTextTextSpanTextSpan2.text, posts[0]['caption']); + checkWidgetProperty( + "text", + postItemCaptionRichTextTextSpanTextSpan2, + postItemCaptionRichTextTextSpanTextSpan2.style, + const TextStyle(fontSize: 15, fontWeight: FontWeight.w500), + ); + + final postItemViewCommentsContainerFinder = find.byKey( + const Key('post_item_view_comments_container'), + ); + checkWidgetDescendantProperty( + postItemColumnFinder, postItemViewCommentsContainerFinder); + + final postItemViewCommentsContainer = postItemViewCommentsContainerFinder + .evaluate() + .first + .widget as Container; + checkWidgetProperty( + "padding", + postItemViewCommentsContainerFinder, + postItemViewCommentsContainer.padding, + const EdgeInsets.symmetric(horizontal: 15), + ); + checkWidgetProperty( + "margin", + postItemViewCommentsContainerFinder, + postItemViewCommentsContainer.margin, + const EdgeInsets.only(bottom: 12), + ); + + final postItemViewCommentsTextFinder = find.byKey( + const Key('post_item_view_comments_text'), + ); + checkWidgetDescendantProperty( + postItemViewCommentsContainerFinder, postItemViewCommentsTextFinder); + + final postItemViewCommentsText = + postItemViewCommentsTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "data", + postItemViewCommentsTextFinder, + postItemViewCommentsText.data, + "View ${posts[0]['commentCount']} comments", + ); + checkByKeyIsWidget(postItemViewCommentsText.style, isA()); + checkWidgetProperty( + "color", + postItemViewCommentsTextFinder, + postItemViewCommentsText.style!.color, + white.withOpacity(0.5), + ); + checkWidgetProperty( + "fontSize", + postItemViewCommentsTextFinder, + postItemViewCommentsText.style!.fontSize, + 15, + ); + checkWidgetProperty( + "fontWeight", + postItemViewCommentsTextFinder, + postItemViewCommentsText.style!.fontWeight, + FontWeight.w500, + ); + + final postItemAddCommentContainerFinder = find.byKey( + const Key('post_item_add_comment_container'), + ); + checkWidgetDescendantProperty( + postItemColumnFinder, postItemAddCommentContainerFinder); + + final postItemAddCommentContainer = postItemAddCommentContainerFinder + .evaluate() + .first + .widget as Container; + checkWidgetProperty( + "padding", + postItemAddCommentContainerFinder, + postItemAddCommentContainer.padding, + const EdgeInsets.symmetric(horizontal: 15), + ); + checkWidgetProperty( + "margin", + postItemAddCommentContainerFinder, + postItemAddCommentContainer.margin, + const EdgeInsets.only(bottom: 12), + ); + + final postItemAddCommentRowFinder = find.byKey( + const Key('post_item_add_comment_row'), + ); + checkWidgetDescendantProperty( + postItemAddCommentContainerFinder, postItemAddCommentRowFinder); + + final postItemAddCommentRow = + postItemAddCommentRowFinder.evaluate().first.widget as Row; + checkWidgetProperty( + "mainAxisAlignment", + postItemAddCommentRowFinder, + postItemAddCommentRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween, + ); + // checkError(150, postItemAddCommentRow.children, hasLength(2)); + + final postItemAddCommentLeftRowFinder = find.byKey( + const Key('post_item_add_comment_left_row'), + ); + checkWidgetDescendantProperty( + postItemAddCommentRowFinder, postItemAddCommentLeftRowFinder); + + // final postItemAddCommentLeftRow = + // postItemAddCommentLeftRowFinder.evaluate().first.widget as Row; + // checkError(152, postItemAddCommentLeftRow.children, hasLength(2)); + + final postItemAddCommentAvatarContainerFinder = find.byKey( + const Key('post_item_add_comment_avatar_container'), + ); + checkWidgetDescendantProperty(postItemAddCommentLeftRowFinder, + postItemAddCommentAvatarContainerFinder); + + final postItemAddCommentAvatarContainer = + postItemAddCommentAvatarContainerFinder.evaluate().first.widget + as Container; + checkWidgetProperty( + "width", + postItemAddCommentAvatarContainerFinder, + postItemAddCommentAvatarContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 30, maxWidth: 30), + ); + checkWidgetProperty( + "height", + postItemAddCommentAvatarContainerFinder, + postItemAddCommentAvatarContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 30, maxHeight: 30), + ); + checkWidgetProperty( + "margin", + postItemAddCommentAvatarContainerFinder, + postItemAddCommentAvatarContainer.margin, + const EdgeInsets.only(right: 15), + ); + checkByKeyIsWidget( + postItemAddCommentAvatarContainer.decoration, isA()); + + final postItemAddCommentAvatarContainerDecoration = + postItemAddCommentAvatarContainer.decoration as BoxDecoration; + checkWidgetProperty( + "shape", + postItemAddCommentAvatarContainerFinder, + postItemAddCommentAvatarContainerDecoration.shape, + BoxShape.circle, + ); + checkByKeyIsWidget(postItemAddCommentAvatarContainerDecoration.image, + isA()); + + final postItemAddCommentAvatarContainerDecorationImage = + postItemAddCommentAvatarContainerDecoration.image as DecorationImage; + checkByKeyIsWidget(postItemAddCommentAvatarContainerDecorationImage.image, + isA()); + checkWidgetProperty( + "DecorationImage.fit", + postItemAddCommentAvatarContainerFinder, + postItemAddCommentAvatarContainerDecorationImage.fit, + BoxFit.cover, + ); + + final postItemAddCommentAvatarContainerDecorationImageNetworkImage = + postItemAddCommentAvatarContainerDecorationImage.image + as NetworkImage; + checkWidgetProperty( + "DecorationImageNetworkImage.url", + postItemAddCommentAvatarContainerFinder, + postItemAddCommentAvatarContainerDecorationImageNetworkImage.url, + profile, + ); + + final postItemAddCommentTextFinder = find.byKey( + const Key('post_item_add_comment_text'), + ); + checkWidgetDescendantProperty( + postItemAddCommentLeftRowFinder, postItemAddCommentTextFinder); + + final postItemAddCommentText = + postItemAddCommentTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "data", + postItemAddCommentTextFinder, + postItemAddCommentText.data, + 'Add a comment...', + ); + checkByKeyIsWidget(postItemAddCommentText.style, isA()); + checkWidgetProperty( + "color", + postItemAddCommentTextFinder, + postItemAddCommentText.style!.color, + white.withOpacity(0.5), + ); + checkWidgetProperty( + "fontSize", + postItemAddCommentTextFinder, + postItemAddCommentText.style!.fontSize, + 15, + ); + checkWidgetProperty( + "fontWeight", + postItemAddCommentTextFinder, + postItemAddCommentText.style!.fontWeight, + FontWeight.w500, + ); + + final postItemAddCommentRightRowFinder = + find.byKey(const Key('post_item_add_comment_right_row')); + checkWidgetDescendantProperty( + postItemAddCommentRowFinder, postItemAddCommentRightRowFinder); + + // final postItemAddCommentRightRow = + // postItemAddCommentRightRowFinder.evaluate().first.widget as Row; + // checkError(170, postItemAddCommentRightRow.children, hasLength(5)); + + final postItemAddLaughEmojiTextFinder = find.byKey( + const Key('post_item_add_laugh_emoji_text'), + ); + checkWidgetDescendantProperty( + postItemAddCommentRightRowFinder, postItemAddLaughEmojiTextFinder); + + final postItemAddLaughEmojiText = + postItemAddLaughEmojiTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "data", + postItemAddLaughEmojiTextFinder, + postItemAddLaughEmojiText.data, + '😂', + ); + checkWidgetProperty( + "style", + postItemAddLaughEmojiTextFinder, + postItemAddLaughEmojiText.style, + const TextStyle(fontSize: 20), + ); + + final postItemAddLoveEmojiTextFinder = find.byKey( + const Key('post_item_add_love_emoji_text'), + ); + checkWidgetDescendantProperty( + postItemAddCommentRightRowFinder, postItemAddLoveEmojiTextFinder); + + final postItemAddLoveEmojiText = + postItemAddLoveEmojiTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "data", + postItemAddLoveEmojiTextFinder, + postItemAddLoveEmojiText.data, + '😍', + ); + checkWidgetProperty( + "style", + postItemAddLoveEmojiTextFinder, + postItemAddLoveEmojiText.style, + const TextStyle(fontSize: 20), + ); + + final postItemAddCircleIconFinder = find.byKey( + const Key('post_item_add_circle_icon'), + ); + checkWidgetDescendantProperty( + postItemAddCommentRightRowFinder, postItemAddCircleIconFinder); + + final postItemAddCircleIcon = + postItemAddCircleIconFinder.evaluate().first.widget as Icon; + checkWidgetProperty( + "icon", + postItemAddCircleIconFinder, + postItemAddCircleIcon.icon, + Icons.add_circle, + ); + checkWidgetProperty( + "size", + postItemAddCircleIconFinder, + postItemAddCircleIcon.size, + 18, + ); + checkWidgetProperty( + "color", + postItemAddCircleIconFinder, + postItemAddCircleIcon.color, + white.withOpacity(0.5), + ); + + final postItemDayAgoPaddingFinder = find.byKey( + const Key('post_item_day_ago_padding'), + ); + checkWidgetDescendantProperty( + postItemColumnFinder, postItemDayAgoPaddingFinder); + + final postItemDayAgoPadding = + postItemDayAgoPaddingFinder.evaluate().first.widget as Padding; + checkWidgetProperty( + "padding", + postItemDayAgoPaddingFinder, + postItemDayAgoPadding.padding, + const EdgeInsets.symmetric(horizontal: 15), + ); + + final postItemDayAgoTextFinder = find.byKey( + const Key('post_item_day_ago_text'), + ); + checkWidgetDescendantProperty( + postItemDayAgoPaddingFinder, postItemDayAgoTextFinder); + + final postItemDayAgoText = + postItemDayAgoTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "data", + postItemDayAgoTextFinder, + postItemDayAgoText.data, + posts[0]['timeAgo'], + ); + checkWidgetProperty( + "color", + postItemDayAgoTextFinder, + postItemDayAgoText.style!.color, + white.withOpacity(0.5), + ); + checkWidgetProperty( + "fontSize", + postItemDayAgoTextFinder, + postItemDayAgoText.style!.fontSize, + 15, + ); + checkWidgetProperty( + "fontWeight", + postItemDayAgoTextFinder, + postItemDayAgoText.style!.fontWeight, + FontWeight.w500, + ); + }, + ); +} diff --git a/clone-instagram-login-Refactoring/test/task_5_test.dart b/clone-instagram-login-Refactoring/test/task_5_test.dart new file mode 100644 index 0000000..e8f4798 --- /dev/null +++ b/clone-instagram-login-Refactoring/test/task_5_test.dart @@ -0,0 +1,1295 @@ +import 'package:example_widget_testing/app/modules/home/components/story_item.dart'; +import 'package:example_widget_testing/app/modules/home/home_page.dart'; +import 'package:example_widget_testing/app/modules/login/login_page.dart'; +import 'package:example_widget_testing/app/widgets/post_item.dart'; +import 'package:example_widget_testing/core/theme/colors.dart'; +import 'package:example_widget_testing/core/values/constant/post_json.dart'; +import 'package:example_widget_testing/core/values/constant/profile_json.dart'; +import 'package:example_widget_testing/core/values/constant/story_json.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network_image_mock/network_image_mock.dart'; + +import 'test_library.dart'; + +void main() { + testWidgets('Check if Task 2 is finished', (WidgetTester tester) async { + FlutterError.onError = unfinishedTaskErrorHandler; + await mockNetworkImagesFor( + () => tester.pumpWidget( + const MaterialApp( + home: LoginPage(), + ), + ), + ); + final loginPageFinder = find.byType(LoginPage); + checkByTypeFindOneWidget(loginPageFinder); + }); + + testWidgets('Check if Task 3 is finished', (WidgetTester tester) async { + FlutterError.onError = unfinishedTaskErrorHandler; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: HomePage( + posts: posts, + profileData: profileJson, + stories: stories, + ), + ), + ), + ); + final homePageFinder = find.byType(HomePage); + checkByTypeFindOneWidget(homePageFinder); + + final appBarFinder = find.byKey(const Key('home_page_appbar')); + checkByKeyFindOneWidget(appBarFinder); + + final appBar = appBarFinder.evaluate().first.widget as AppBar; + checkWidgetProperty( + "backgroundColor", appBar, appBar.backgroundColor, Colors.black); + checkByKeyIsWidget(appBar.leading, isA()); + + final appBarLeading = appBar.leading as Icon; + checkWidgetProperty("icon", appBar, appBarLeading.icon, Icons.camera_alt); + checkByKeyIsWidget(appBar.title, isA
()); + + final appBarTitle = appBar.title as Center; + checkByKeyIsWidget(appBarTitle.child, isA()); + checkByKeyIsWidget(appBar.actions, isA>()); + // checkError(9, appBar.actions?.length, 1); + + final appBarAction = appBar.actions?.first as Icon; + checkWidgetProperty("icon", appBar, appBarAction.icon, Icons.send); + + final storyFinder = find.byKey(const Key('following_stories_row')); + checkByKeyFindOneWidget(storyFinder); + + final story = storyFinder.evaluate().first.widget as Row; + checkByKeyIsWidget(story.children, isA>()); + checkWidgetProperty( + "length", storyFinder, story.children.length, stories.length); + checkByKeyIsWidget(story.children[0], isA()); + + stories.asMap().forEach((index, value) { + final storyItem = story.children[index] as StoryItem; + checkWidgetProperty("name", storyFinder, storyItem.name, value['name']); + checkWidgetProperty("img", storyFinder, storyItem.img, value['img']); + }); + + const String imageUrl = 'https://example.com/image.jpg'; + const String name = 'John Doe'; + + FlutterError.onError = customFlutterErrorHandler; + + await mockNetworkImagesFor(() => tester.pumpWidget( + const MaterialApp(home: StoryItem(img: imageUrl, name: name)))); + + // checkError(17, find.byType(Container), findsNWidgets(2)); + + final storyItemPaddingFinder = find.byKey(const Key('story_item_padding')); + checkByKeyFindOneWidget(storyItemPaddingFinder); + + final storyItemPadding = + storyItemPaddingFinder.evaluate().first.widget as Padding; + checkWidgetProperty( + "padding", + storyItemPaddingFinder, + storyItemPadding.padding, + const EdgeInsets.only(right: 20, bottom: 10), + ); + + final storyItemColumnFinder = find.byKey(const Key('story_item_column')); + checkByKeyFindOneWidget(storyItemColumnFinder); + checkWidgetDescendantProperty( + storyItemPaddingFinder, storyItemColumnFinder); + + final storyItemColumn = + storyItemColumnFinder.evaluate().first.widget as Column; + checkByKeyIsWidget(storyItemColumn.children, isA>()); + // checkError(23, storyItemColumn.children.length, 2); + + final storyItemContainerFinder = find.byKey( + const Key('story_item_container'), + ); + checkWidgetDescendantProperty( + storyItemColumnFinder, storyItemContainerFinder); + + final storyItemContainer = + storyItemContainerFinder.evaluate().first.widget as Container; + + checkWidgetProperty( + "width", + storyItemContainerFinder, + storyItemContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 68, maxWidth: 68), + ); + + checkWidgetProperty( + "margin", + storyItemContainerFinder, + storyItemContainer.margin, + const EdgeInsets.only(bottom: 8), + ); + + checkWidgetProperty( + "height", + storyItemContainerFinder, + storyItemContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 68, maxHeight: 68), + ); + + checkByKeyIsWidget(storyItemContainer.decoration, isA()); + + final storyItemContainerDecoration = + storyItemContainer.decoration as BoxDecoration; + checkWidgetProperty( + "shape", + storyItemContainerFinder, + storyItemContainerDecoration.shape, + BoxShape.circle, + ); + + checkByKeyIsWidget( + storyItemContainerDecoration.gradient, isA()); + final storyItemContainerGradient = + storyItemContainerDecoration.gradient as LinearGradient; + checkWidgetProperty( + "begin", + storyItemContainerFinder, + storyItemContainerGradient.begin, + Alignment.topCenter, + ); + checkWidgetProperty( + 'end', + storyItemContainerFinder, + storyItemContainerGradient.end, + Alignment.bottomCenter, + ); + checkWidgetProperty( + "colors", + storyItemContainerFinder, + storyItemContainerGradient.colors, + const [Color(0xFF9B2282), Color(0xFFEEA863)], + ); + + final storyItemImageContainerFinder = find.byKey( + const Key('story_item_image_container'), + ); + + checkWidgetDescendantProperty( + storyItemContainerFinder, storyItemImageContainerFinder); + + final storyItemImageContainer = + storyItemImageContainerFinder.evaluate().first.widget as Container; + + checkWidgetProperty( + "width", + storyItemImageContainerFinder, + storyItemImageContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 65, maxWidth: 65), + ); + + checkWidgetProperty( + "height", + storyItemImageContainerFinder, + storyItemImageContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 65, maxHeight: 65), + ); + + checkWidgetProperty( + "margin", + storyItemImageContainerFinder, + storyItemImageContainer.margin, + const EdgeInsets.all(3), + ); + + checkByKeyIsWidget( + storyItemImageContainer.decoration, isA()); + + final storyItemImageContainerDecoration = + storyItemImageContainer.decoration as BoxDecoration; + checkWidgetProperty( + "shape", + storyItemImageContainerFinder, + storyItemImageContainerDecoration.shape, + BoxShape.circle, + ); + checkWidgetProperty( + "border", + storyItemImageContainerFinder, + storyItemImageContainerDecoration.border, + const Border.fromBorderSide( + BorderSide( + color: black, + width: 2, + style: BorderStyle.solid, + ), + ), + ); + + checkByKeyIsWidget( + storyItemImageContainerDecoration.image, isA()); + + final storyItemImageContainerDecorationImage = + (storyItemImageContainer.decoration as BoxDecoration).image + as DecorationImage; + checkByKeyIsWidget( + storyItemImageContainerDecorationImage.image, isA()); + + checkWidgetProperty( + "fit", + storyItemImageContainerFinder, + storyItemImageContainerDecorationImage.fit, + BoxFit.cover, + ); + + final storyItemUsernameSizeBoxFinder = find.byKey( + const Key('story_item_username_sizedbox'), + ); + + checkWidgetDescendantProperty( + storyItemColumnFinder, storyItemUsernameSizeBoxFinder); + + final storyItemUsernameSizeBox = + storyItemUsernameSizeBoxFinder.evaluate().first.widget as SizedBox; + checkWidgetProperty( + "width", + storyItemUsernameSizeBoxFinder, + storyItemUsernameSizeBox.width, + 70, + ); + + final storyItemUsernameTextFinder = find.byKey( + const Key('story_item_username_text'), + ); + + checkWidgetDescendantProperty( + storyItemUsernameSizeBoxFinder, storyItemUsernameTextFinder); + + final storyItemUsernameText = + storyItemUsernameTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "data", + storyItemUsernameTextFinder, + storyItemUsernameText.data, + name, + ); + checkWidgetProperty( + "overflow", + storyItemUsernameTextFinder, + storyItemUsernameText.overflow, + TextOverflow.ellipsis, + ); + checkWidgetProperty( + "color", + storyItemUsernameTextFinder, + storyItemUsernameText.style!.color, + white, + ); + + await tester.pumpWidget( + MaterialApp( + home: HomePage( + posts: posts, + profileData: profileJson, + stories: stories, + ), + ), + ); + + final dividerFinder = find.byKey(const Key('home_page_divider')); + checkByKeyFindOneWidget(dividerFinder); + + final divider = dividerFinder.evaluate().first.widget as Divider; + checkWidgetProperty( + "color", + dividerFinder, + divider.color, + white.withOpacity(0.3), + ); + }); + + testWidgets('Check if Task 4 is finished', (WidgetTester tester) async { + FlutterError.onError = unfinishedTaskErrorHandler; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: HomePage( + posts: posts, + profileData: profileJson, + stories: stories, + ), + ), + ), + ); + + final homePageColumnFinder = find.byKey(const Key('home_page_column')); + final postsColumnFinder = find.byKey(const Key('posts_column')); + checkWidgetDescendantProperty(homePageColumnFinder, postsColumnFinder); + checkByKeyFindOneWidget(postsColumnFinder); + + final postsColumn = postsColumnFinder.evaluate().first.widget as Column; + checkError(53, postsColumn.children.length, posts.length); + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: PostItem( + postImg: posts[0]['postImg'], + profileImg: posts[0]['profileImg'], + name: posts[0]['name'], + caption: posts[0]['caption'], + isLoved: posts[0]['isLoved'], + viewCount: posts[0]['commentCount'], + likedBy: posts[0]['likedBy'], + dayAgo: posts[0]['timeAgo'], + userPhoto: profile, + onPressed: () {}, + ), + ), + ), + ); + + final postItemPaddingFinder = find.byKey(const Key('post_item_padding')); + checkByKeyFindOneWidget(postItemPaddingFinder); + + final postItemPadding = + postItemPaddingFinder.evaluate().first.widget as Padding; + checkWidgetProperty( + "padding", + postItemPaddingFinder, + postItemPadding.padding, + const EdgeInsets.only(bottom: 10), + ); + + final postItemColumnFinder = find.byKey(const Key('post_item_column')); + checkWidgetDescendantProperty(postItemPaddingFinder, postItemColumnFinder); + + final postItemColumn = + postItemColumnFinder.evaluate().first.widget as Column; + checkWidgetProperty( + "crossAxisAlignment", + postItemColumnFinder, + postItemColumn.crossAxisAlignment, + CrossAxisAlignment.start, + ); + // checkError(58, postItemColumn.children.length, 8); + + final postItemUserInfoContainerFinder = find.byKey( + const Key('post_item_user_info_container'), + ); + checkWidgetDescendantProperty( + postItemColumnFinder, postItemUserInfoContainerFinder); + + final postItemUserInfoContainer = + postItemUserInfoContainerFinder.evaluate().first.widget as Container; + checkWidgetProperty( + "padding", + postItemUserInfoContainerFinder, + postItemUserInfoContainer.padding, + const EdgeInsets.symmetric(vertical: 10, horizontal: 15), + ); + + checkWidgetProperty( + "margin", + postItemUserInfoContainerFinder, + postItemUserInfoContainer.margin, + const EdgeInsets.only(bottom: 12), + ); + + final postItemUserInfoRowFinder = find.byKey( + const Key('post_item_user_info_row'), + ); + checkWidgetDescendantProperty( + postItemUserInfoContainerFinder, postItemUserInfoRowFinder); + + final postItemUserInfoRow = + postItemUserInfoRowFinder.evaluate().first.widget as Row; + checkWidgetProperty( + "mainAxisAlignment", + postItemUserInfoRowFinder, + postItemUserInfoRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween, + ); + // checkError(64, postItemUserInfoRow.children.length, 3); + + final postItemUserImgContainerFinder = find.byKey( + const Key('post_item_user_profile_img_container'), + ); + checkWidgetDescendantProperty( + postItemUserInfoRowFinder, postItemUserImgContainerFinder); + + final postItemUserImgContainer = + postItemUserImgContainerFinder.evaluate().first.widget as Container; + checkWidgetProperty( + "width", + postItemUserImgContainerFinder, + postItemUserImgContainer.constraints!.maxWidth, + 40, + ); + checkWidgetProperty( + "height", + postItemUserImgContainerFinder, + postItemUserImgContainer.constraints!.maxHeight, + 40, + ); + checkWidgetProperty( + "margin", + postItemUserImgContainerFinder, + postItemUserImgContainer.margin, + const EdgeInsets.only(right: 15), + ); + checkByKeyIsWidget( + postItemUserImgContainer.decoration, isA()); + + final postItemUserImgContainerDecoration = + postItemUserImgContainer.decoration as BoxDecoration; + checkWidgetProperty( + "shape", + postItemUserImgContainerFinder, + postItemUserImgContainerDecoration.shape, + BoxShape.circle, + ); + checkByKeyIsWidget( + postItemUserImgContainerDecoration.image, + isA(), + ); + + final postItemUserImgContainerDecorationImage = + postItemUserImgContainerDecoration.image as DecorationImage; + checkByKeyIsWidget( + postItemUserImgContainerDecorationImage.image, isA()); + checkWidgetProperty( + "fit", + postItemUserImgContainerFinder, + postItemUserImgContainerDecorationImage.fit, + BoxFit.cover, + ); + + final postItemUserImgContainerDecorationImageNetworkImage = + postItemUserImgContainerDecorationImage.image as NetworkImage; + checkWidgetProperty( + "ImageNetworkImage.url", + postItemUserImgContainerFinder, + postItemUserImgContainerDecorationImageNetworkImage.url, + posts[0]['profileImg'], + ); + + final postItemUserNameExpendedFinder = find.byKey( + const Key('post_item_user_name_expanded'), + ); + checkWidgetDescendantProperty( + postItemUserInfoRowFinder, postItemUserNameExpendedFinder); + + final postItemUserNameTextFinder = find.byKey( + const Key('post_item_user_name_text'), + ); + checkWidgetDescendantProperty( + postItemUserNameExpendedFinder, postItemUserNameTextFinder); + + final postItemUserNameText = + postItemUserNameTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "data", + postItemUserNameTextFinder, + postItemUserNameText.data, + posts[0]['name'], + ); + checkByKeyIsWidget(postItemUserNameText.style, isA()); + + final postItemUserNameTextStyle = postItemUserNameText.style as TextStyle; + checkWidgetProperty( + "color", + postItemUserNameTextFinder, + postItemUserNameTextStyle.color, + Colors.white, + ); + checkWidgetProperty( + "fontWeight", + postItemUserNameTextFinder, + postItemUserNameTextStyle.fontWeight, + FontWeight.w500, + ); + checkWidgetProperty( + "fontSize", + postItemUserNameTextFinder, + postItemUserNameTextStyle.fontSize, + 15, + ); + + final postItemUserMoreIconFinder = find.byKey( + const Key('post_item_user_more_icon'), + ); + checkWidgetDescendantProperty( + postItemUserInfoRowFinder, postItemUserMoreIconFinder); + + final postItemUserMoreIcon = + postItemUserMoreIconFinder.evaluate().first.widget as Icon; + checkWidgetProperty( + "icon", + postItemUserMoreIconFinder, + postItemUserMoreIcon.icon, + Icons.more_horiz, + ); + checkWidgetProperty( + "color", + postItemUserMoreIconFinder, + postItemUserMoreIcon.color, + Colors.white, + ); + + final postItemImageContainerFinder = find.byKey( + const Key('post_item_image_container'), + ); + checkWidgetDescendantProperty( + postItemColumnFinder, postItemImageContainerFinder); + + final postItemImageContainer = + postItemImageContainerFinder.evaluate().first.widget as Container; + checkWidgetProperty( + "height", + postItemImageContainerFinder, + postItemImageContainer.constraints!.maxHeight, + 400, + ); + checkWidgetProperty( + "margin", + postItemImageContainerFinder, + postItemImageContainer.margin, + const EdgeInsets.only(bottom: 10), + ); + checkByKeyIsWidget(postItemImageContainer.decoration, isA()); + + final postItemImageContainerDecoration = + postItemImageContainer.decoration as BoxDecoration; + checkByKeyIsWidget( + postItemImageContainerDecoration.image, isA()); + + final postItemImageContainerDecorationImage = + postItemImageContainerDecoration.image as DecorationImage; + checkByKeyIsWidget( + postItemImageContainerDecorationImage.image, isA()); + checkWidgetProperty( + "fit", + postItemImageContainerFinder, + postItemImageContainerDecorationImage.fit, + BoxFit.cover, + ); + + final postItemImageContainerDecorationImageNetworkImage = + postItemImageContainerDecorationImage.image as NetworkImage; + checkWidgetProperty( + "ImageNetworkImage.url", + postItemImageContainerFinder, + postItemImageContainerDecorationImageNetworkImage.url, + posts[0]['postImg'], + ); + + final postItemActionContainerFinder = + find.byKey(const Key('post_item_actions_container')); + checkWidgetDescendantProperty( + postItemColumnFinder, postItemActionContainerFinder); + + final postItemActionContainer = + postItemActionContainerFinder.evaluate().first.widget as Container; + checkWidgetProperty( + "padding", + postItemActionContainerFinder, + postItemActionContainer.padding, + const EdgeInsets.fromLTRB(15, 3, 15, 0), + ); + checkWidgetProperty( + "margin", + postItemActionContainerFinder, + postItemActionContainer.margin, + const EdgeInsets.only(bottom: 12), + ); + + final postItemActionRowFinder = find.byKey( + const Key('post_item_actions_row'), + ); + checkWidgetDescendantProperty( + postItemActionContainerFinder, + postItemActionRowFinder, + ); + + final postItemActionRow = + postItemActionRowFinder.evaluate().first.widget as Row; + checkWidgetProperty( + "mainAxisAlignment", + postItemActionRowFinder, + postItemActionRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween, + ); + // checkError(98, postItemActionRow.children.length, 2); + + final postItemActionsLeftRowFinder = find.byKey( + const Key('post_item_actions_left_row'), + ); + checkWidgetDescendantProperty( + postItemActionRowFinder, postItemActionsLeftRowFinder); + + // final postItemActionsLeftRow = + // postItemActionsLeftRowFinder.evaluate().first.widget as Row; + // checkError(100, postItemActionsLeftRow.children.length, 5); + + final postItemActionsLoveIconFinder = find.byKey( + const Key('post_item_actions_love_icon'), + ); + checkWidgetDescendantProperty( + postItemActionsLeftRowFinder, postItemActionsLoveIconFinder); + + final postItemActionsLoveIcon = + postItemActionsLoveIconFinder.evaluate().first.widget as SvgPicture; + checkByKeyIsWidget(postItemActionsLoveIcon, isA()); + checkWidgetProperty( + "width", + postItemActionsLoveIconFinder, + postItemActionsLoveIcon.width, + 27, + ); + checkWidgetProperty( + "pictureProvider.runtimeType", + postItemActionsLoveIconFinder, + postItemActionsLoveIcon.pictureProvider.runtimeType, + ExactAssetPicture, + ); + + final postItemActionsLoveIconPictureProvider = + postItemActionsLoveIcon.pictureProvider as ExactAssetPicture; + checkWidgetProperty( + "assetName", + postItemActionsLoveIconFinder, + postItemActionsLoveIconPictureProvider.assetName, + posts[0]['isLoved'] + ? 'assets/images/loved_icon.svg' + : 'assets/images/love_icon.svg', + ); + final postItemActionsLeftRowSizeBox1Finder = find.byKey( + const Key('post_item_actions_left_row_sized_box_1'), + ); + checkWidgetDescendantProperty( + postItemActionsLeftRowFinder, postItemActionsLeftRowSizeBox1Finder); + + final postItemActionsLeftRowSizeBox1 = postItemActionsLeftRowSizeBox1Finder + .evaluate() + .first + .widget as SizedBox; + checkWidgetProperty( + "width", + postItemActionsLeftRowSizeBox1Finder, + postItemActionsLeftRowSizeBox1.width, + 20, + ); + + final postItemActionsCommentIconFinder = find.byKey( + const Key('post_item_actions_comment_icon'), + ); + checkWidgetDescendantProperty( + postItemActionsLeftRowFinder, postItemActionsCommentIconFinder); + + final postItemActionsCommentIcon = + postItemActionsCommentIconFinder.evaluate().first.widget as SvgPicture; + checkByKeyIsWidget(postItemActionsCommentIcon, isA()); + checkWidgetProperty( + "width", + postItemActionsCommentIconFinder, + postItemActionsCommentIcon.width, + 27, + ); + checkWidgetProperty( + "pictureProvider.runtimeType", + postItemActionsCommentIconFinder, + postItemActionsCommentIcon.pictureProvider.runtimeType, + ExactAssetPicture, + ); + + final postItemActionsCommentIconPictureProvider = + postItemActionsCommentIcon.pictureProvider as ExactAssetPicture; + checkWidgetProperty( + "assetName", + postItemActionsCommentIconFinder, + postItemActionsCommentIconPictureProvider.assetName, + "assets/images/comment_icon.svg", + ); + + final postItemActionsLeftRowSizeBox2Finder = find.byKey( + const Key('post_item_actions_left_row_sized_box_2'), + ); + checkWidgetDescendantProperty( + postItemActionsLeftRowFinder, postItemActionsLeftRowSizeBox2Finder); + + final postItemActionsLeftRowSizeBox2 = postItemActionsLeftRowSizeBox2Finder + .evaluate() + .first + .widget as SizedBox; + checkWidgetProperty( + "width", + postItemActionsLeftRowSizeBox2Finder, + postItemActionsLeftRowSizeBox2.width, + 20, + ); + + final postItemActionsMessageIconFinder = find.byKey( + const Key('post_item_actions_message_icon'), + ); + checkWidgetDescendantProperty( + postItemActionsLeftRowFinder, postItemActionsMessageIconFinder); + + final postItemActionsMessageIcon = + postItemActionsMessageIconFinder.evaluate().first.widget as SvgPicture; + checkByKeyIsWidget(postItemActionsMessageIcon, isA()); + checkWidgetProperty( + "width", + postItemActionsMessageIconFinder, + postItemActionsMessageIcon.width, + 27, + ); + checkWidgetProperty( + "pictureProvider.runtimeType", + postItemActionsMessageIconFinder, + postItemActionsMessageIcon.pictureProvider.runtimeType, + ExactAssetPicture, + ); + + final postItemActionsMessageIconPictureProvider = + postItemActionsMessageIcon.pictureProvider as ExactAssetPicture; + checkWidgetProperty( + "assetName", + postItemActionsMessageIconFinder, + postItemActionsMessageIconPictureProvider.assetName, + "assets/images/message_icon.svg", + ); + + final postItemActionsSaveIconFinder = find.byKey( + const Key('post_item_actions_save_icon'), + ); + checkWidgetDescendantProperty( + postItemActionRowFinder, postItemActionsSaveIconFinder); + + final postItemActionsSaveIcon = + postItemActionsSaveIconFinder.evaluate().first.widget as SvgPicture; + checkByKeyIsWidget(postItemActionsSaveIcon, isA()); + checkWidgetProperty( + "width", + postItemActionsSaveIconFinder, + postItemActionsSaveIcon.width, + 27, + ); + checkWidgetProperty( + "pictureProvider.runtimeType", + postItemActionsSaveIconFinder, + postItemActionsSaveIcon.pictureProvider.runtimeType, + ExactAssetPicture); + + final postItemActionsSaveIconPictureProvider = + postItemActionsSaveIcon.pictureProvider as ExactAssetPicture; + checkWidgetProperty( + "assetName", + postItemActionsSaveIconFinder, + postItemActionsSaveIconPictureProvider.assetName, + "assets/images/save_icon.svg", + ); + + final postItemCaptionContainerFinder = find.byKey( + const Key('post_item_caption_container'), + ); + checkWidgetDescendantProperty( + postItemColumnFinder, + postItemCaptionContainerFinder, + ); + + final postItemCaptionContainer = + postItemCaptionContainerFinder.evaluate().first.widget as Container; + checkByKeyIsWidget(postItemCaptionContainer, isA()); + checkWidgetProperty( + "padding", + postItemCaptionContainerFinder, + postItemCaptionContainer.padding, + const EdgeInsets.symmetric(horizontal: 15), + ); + checkWidgetProperty( + "margin", + postItemCaptionContainerFinder, + postItemCaptionContainer.margin, + const EdgeInsets.only(bottom: 12), + ); + + final postItemCaptionRichTextFinder = find.byKey( + const Key('post_item_caption_rich_text'), + ); + checkWidgetDescendantProperty( + postItemCaptionContainerFinder, postItemCaptionRichTextFinder); + + final postItemCaptionRichText = + postItemCaptionRichTextFinder.evaluate().first.widget as RichText; + checkByKeyIsWidget(postItemCaptionRichText.text, isA()); + + final postItemCaptionRichTextTextSpan = + postItemCaptionRichText.text as TextSpan; + // checkError(131, postItemCaptionRichTextTextSpan.children, hasLength(2)); + + final postItemCaptionRichTextTextSpanTextSpan1 = + postItemCaptionRichTextTextSpan.children![0] as TextSpan; + checkWidgetProperty("text", postItemCaptionRichTextTextSpanTextSpan1, + postItemCaptionRichTextTextSpanTextSpan1.text, posts[0]['name'] + ' '); + checkWidgetProperty( + "text", + postItemCaptionRichTextTextSpanTextSpan1, + postItemCaptionRichTextTextSpanTextSpan1.style, + const TextStyle(fontSize: 15, fontWeight: FontWeight.w700), + ); + + final postItemCaptionRichTextTextSpanTextSpan2 = + postItemCaptionRichTextTextSpan.children![1] as TextSpan; + checkWidgetProperty("text", postItemCaptionRichTextTextSpanTextSpan2, + postItemCaptionRichTextTextSpanTextSpan2.text, posts[0]['caption']); + checkWidgetProperty( + "text", + postItemCaptionRichTextTextSpanTextSpan2, + postItemCaptionRichTextTextSpanTextSpan2.style, + const TextStyle(fontSize: 15, fontWeight: FontWeight.w500), + ); + + final postItemViewCommentsContainerFinder = find.byKey( + const Key('post_item_view_comments_container'), + ); + checkWidgetDescendantProperty( + postItemColumnFinder, postItemViewCommentsContainerFinder); + + final postItemViewCommentsContainer = postItemViewCommentsContainerFinder + .evaluate() + .first + .widget as Container; + checkWidgetProperty( + "padding", + postItemViewCommentsContainerFinder, + postItemViewCommentsContainer.padding, + const EdgeInsets.symmetric(horizontal: 15), + ); + checkWidgetProperty( + "margin", + postItemViewCommentsContainerFinder, + postItemViewCommentsContainer.margin, + const EdgeInsets.only(bottom: 12), + ); + + final postItemViewCommentsTextFinder = find.byKey( + const Key('post_item_view_comments_text'), + ); + checkWidgetDescendantProperty( + postItemViewCommentsContainerFinder, postItemViewCommentsTextFinder); + + final postItemViewCommentsText = + postItemViewCommentsTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "data", + postItemViewCommentsTextFinder, + postItemViewCommentsText.data, + "View ${posts[0]['commentCount']} comments", + ); + checkByKeyIsWidget(postItemViewCommentsText.style, isA()); + checkWidgetProperty( + "color", + postItemViewCommentsTextFinder, + postItemViewCommentsText.style!.color, + white.withOpacity(0.5), + ); + checkWidgetProperty( + "fontSize", + postItemViewCommentsTextFinder, + postItemViewCommentsText.style!.fontSize, + 15, + ); + checkWidgetProperty( + "fontWeight", + postItemViewCommentsTextFinder, + postItemViewCommentsText.style!.fontWeight, + FontWeight.w500, + ); + + final postItemAddCommentContainerFinder = find.byKey( + const Key('post_item_add_comment_container'), + ); + checkWidgetDescendantProperty( + postItemColumnFinder, postItemAddCommentContainerFinder); + + final postItemAddCommentContainer = + postItemAddCommentContainerFinder.evaluate().first.widget as Container; + checkWidgetProperty( + "padding", + postItemAddCommentContainerFinder, + postItemAddCommentContainer.padding, + const EdgeInsets.symmetric(horizontal: 15), + ); + checkWidgetProperty( + "margin", + postItemAddCommentContainerFinder, + postItemAddCommentContainer.margin, + const EdgeInsets.only(bottom: 12), + ); + + final postItemAddCommentRowFinder = find.byKey( + const Key('post_item_add_comment_row'), + ); + checkWidgetDescendantProperty( + postItemAddCommentContainerFinder, postItemAddCommentRowFinder); + + final postItemAddCommentRow = + postItemAddCommentRowFinder.evaluate().first.widget as Row; + checkWidgetProperty( + "mainAxisAlignment", + postItemAddCommentRowFinder, + postItemAddCommentRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween, + ); + // checkError(150, postItemAddCommentRow.children, hasLength(2)); + + final postItemAddCommentLeftRowFinder = find.byKey( + const Key('post_item_add_comment_left_row'), + ); + checkWidgetDescendantProperty( + postItemAddCommentRowFinder, postItemAddCommentLeftRowFinder); + + // final postItemAddCommentLeftRow = + // postItemAddCommentLeftRowFinder.evaluate().first.widget as Row; + // checkError(152, postItemAddCommentLeftRow.children, hasLength(2)); + + final postItemAddCommentAvatarContainerFinder = find.byKey( + const Key('post_item_add_comment_avatar_container'), + ); + checkWidgetDescendantProperty(postItemAddCommentLeftRowFinder, + postItemAddCommentAvatarContainerFinder); + + final postItemAddCommentAvatarContainer = + postItemAddCommentAvatarContainerFinder.evaluate().first.widget + as Container; + checkWidgetProperty( + "width", + postItemAddCommentAvatarContainerFinder, + postItemAddCommentAvatarContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 30, maxWidth: 30), + ); + checkWidgetProperty( + "height", + postItemAddCommentAvatarContainerFinder, + postItemAddCommentAvatarContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 30, maxHeight: 30), + ); + checkWidgetProperty( + "margin", + postItemAddCommentAvatarContainerFinder, + postItemAddCommentAvatarContainer.margin, + const EdgeInsets.only(right: 15), + ); + checkByKeyIsWidget( + postItemAddCommentAvatarContainer.decoration, isA()); + + final postItemAddCommentAvatarContainerDecoration = + postItemAddCommentAvatarContainer.decoration as BoxDecoration; + checkWidgetProperty( + "shape", + postItemAddCommentAvatarContainerFinder, + postItemAddCommentAvatarContainerDecoration.shape, + BoxShape.circle, + ); + checkByKeyIsWidget(postItemAddCommentAvatarContainerDecoration.image, + isA()); + + final postItemAddCommentAvatarContainerDecorationImage = + postItemAddCommentAvatarContainerDecoration.image as DecorationImage; + checkByKeyIsWidget(postItemAddCommentAvatarContainerDecorationImage.image, + isA()); + checkWidgetProperty( + "DecorationImage.fit", + postItemAddCommentAvatarContainerFinder, + postItemAddCommentAvatarContainerDecorationImage.fit, + BoxFit.cover, + ); + + final postItemAddCommentAvatarContainerDecorationImageNetworkImage = + postItemAddCommentAvatarContainerDecorationImage.image as NetworkImage; + checkWidgetProperty( + "DecorationImageNetworkImage.url", + postItemAddCommentAvatarContainerFinder, + postItemAddCommentAvatarContainerDecorationImageNetworkImage.url, + profile, + ); + + final postItemAddCommentTextFinder = find.byKey( + const Key('post_item_add_comment_text'), + ); + checkWidgetDescendantProperty( + postItemAddCommentLeftRowFinder, postItemAddCommentTextFinder); + + final postItemAddCommentText = + postItemAddCommentTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "data", + postItemAddCommentTextFinder, + postItemAddCommentText.data, + 'Add a comment...', + ); + checkByKeyIsWidget(postItemAddCommentText.style, isA()); + checkWidgetProperty( + "color", + postItemAddCommentTextFinder, + postItemAddCommentText.style!.color, + white.withOpacity(0.5), + ); + checkWidgetProperty( + "fontSize", + postItemAddCommentTextFinder, + postItemAddCommentText.style!.fontSize, + 15, + ); + checkWidgetProperty( + "fontWeight", + postItemAddCommentTextFinder, + postItemAddCommentText.style!.fontWeight, + FontWeight.w500, + ); + + final postItemAddCommentRightRowFinder = + find.byKey(const Key('post_item_add_comment_right_row')); + checkWidgetDescendantProperty( + postItemAddCommentRowFinder, postItemAddCommentRightRowFinder); + + // final postItemAddCommentRightRow = + // postItemAddCommentRightRowFinder.evaluate().first.widget as Row; + // checkError(170, postItemAddCommentRightRow.children, hasLength(5)); + + final postItemAddLaughEmojiTextFinder = find.byKey( + const Key('post_item_add_laugh_emoji_text'), + ); + checkWidgetDescendantProperty( + postItemAddCommentRightRowFinder, postItemAddLaughEmojiTextFinder); + + final postItemAddLaughEmojiText = + postItemAddLaughEmojiTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "data", + postItemAddLaughEmojiTextFinder, + postItemAddLaughEmojiText.data, + '😂', + ); + checkWidgetProperty( + "style", + postItemAddLaughEmojiTextFinder, + postItemAddLaughEmojiText.style, + const TextStyle(fontSize: 20), + ); + + final postItemAddLoveEmojiTextFinder = find.byKey( + const Key('post_item_add_love_emoji_text'), + ); + checkWidgetDescendantProperty( + postItemAddCommentRightRowFinder, postItemAddLoveEmojiTextFinder); + + final postItemAddLoveEmojiText = + postItemAddLoveEmojiTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "data", + postItemAddLoveEmojiTextFinder, + postItemAddLoveEmojiText.data, + '😍', + ); + checkWidgetProperty( + "style", + postItemAddLoveEmojiTextFinder, + postItemAddLoveEmojiText.style, + const TextStyle(fontSize: 20), + ); + + final postItemAddCircleIconFinder = find.byKey( + const Key('post_item_add_circle_icon'), + ); + checkWidgetDescendantProperty( + postItemAddCommentRightRowFinder, postItemAddCircleIconFinder); + + final postItemAddCircleIcon = + postItemAddCircleIconFinder.evaluate().first.widget as Icon; + checkWidgetProperty( + "icon", + postItemAddCircleIconFinder, + postItemAddCircleIcon.icon, + Icons.add_circle, + ); + checkWidgetProperty( + "size", + postItemAddCircleIconFinder, + postItemAddCircleIcon.size, + 18, + ); + checkWidgetProperty( + "color", + postItemAddCircleIconFinder, + postItemAddCircleIcon.color, + white.withOpacity(0.5), + ); + + final postItemDayAgoPaddingFinder = find.byKey( + const Key('post_item_day_ago_padding'), + ); + checkWidgetDescendantProperty( + postItemColumnFinder, postItemDayAgoPaddingFinder); + + final postItemDayAgoPadding = + postItemDayAgoPaddingFinder.evaluate().first.widget as Padding; + checkWidgetProperty( + "padding", + postItemDayAgoPaddingFinder, + postItemDayAgoPadding.padding, + const EdgeInsets.symmetric(horizontal: 15), + ); + + final postItemDayAgoTextFinder = find.byKey( + const Key('post_item_day_ago_text'), + ); + checkWidgetDescendantProperty( + postItemDayAgoPaddingFinder, postItemDayAgoTextFinder); + + final postItemDayAgoText = + postItemDayAgoTextFinder.evaluate().first.widget as Text; + checkWidgetProperty( + "data", + postItemDayAgoTextFinder, + postItemDayAgoText.data, + posts[0]['timeAgo'], + ); + checkWidgetProperty( + "color", + postItemDayAgoTextFinder, + postItemDayAgoText.style!.color, + white.withOpacity(0.5), + ); + checkWidgetProperty( + "fontSize", + postItemDayAgoTextFinder, + postItemDayAgoText.style!.fontSize, + 15, + ); + checkWidgetProperty( + "fontWeight", + postItemDayAgoTextFinder, + postItemDayAgoText.style!.fontWeight, + FontWeight.w500, + ); + }); + testWidgets('Check if Bottom Navbar is present', (WidgetTester tester) async { + FlutterError.onError = customFlutterErrorHandler; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: HomePage( + posts: posts, + profileData: profileJson, + stories: stories, + ), + ), + ), + ); + + int pageIndex = 0; + + List bottomItems = [ + pageIndex == 0 + ? "assets/images/home_active_icon.svg" + : "assets/images/home_icon.svg", + pageIndex == 1 + ? "assets/images/search_active_icon.svg" + : "assets/images/search_icon.svg", + pageIndex == 2 + ? "assets/images/upload_active_icon.svg" + : "assets/images/upload_icon.svg", + pageIndex == 3 + ? "assets/images/love_active_icon.svg" + : "assets/images/love_icon.svg", + pageIndex == 4 + ? "assets/images/account_active_icon.svg" + : "assets/images/account_icon.svg", + ]; + + final bottomNavigationBarContainer = + find.byKey(const Key('bottom_navigation_bar_container')); + checkByKeyFindOneWidget(bottomNavigationBarContainer); + + final bottomNavigationBarContainerFinder = + bottomNavigationBarContainer.evaluate().first.widget as Container; + checkWidgetProperty( + "maxHeight", + bottomNavigationBarContainerFinder, + bottomNavigationBarContainerFinder.constraints!.maxHeight, + 55, + ); + checkWidgetProperty( + "maxWidth", + bottomNavigationBarContainerFinder, + bottomNavigationBarContainerFinder.constraints!.maxWidth, + double.infinity, + ); + checkWidgetProperty( + "color", + bottomNavigationBarContainerFinder, + bottomNavigationBarContainerFinder.color, + black, + ); + checkWidgetProperty( + "padding", + bottomNavigationBarContainerFinder, + bottomNavigationBarContainerFinder.padding, + const EdgeInsets.only(left: 20, right: 20, bottom: 20, top: 15), + ); + + final bottomNavigationBarRowFinder = + find.byKey(const Key('bottom_navigation_bar_row')); + checkWidgetDescendantProperty( + bottomNavigationBarContainer, + bottomNavigationBarRowFinder, + ); + + final bottomNavigationBarRow = + bottomNavigationBarRowFinder.evaluate().first.widget as Row; + checkWidgetProperty( + "mainAxisAlignment", + bottomNavigationBarRow, + bottomNavigationBarRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween, + ); + // checkError(195, bottomNavigationBarRow.children, hasLength(5)); + + bottomItems.asMap().forEach((index, value) { + final bottomItem = bottomNavigationBarRow.children[index] as InkWell; + checkByKeyIsWidget(bottomItem.onTap, isA()); + checkByKeyIsWidget(bottomItem.child, isA()); + + final bottomItemSvgPicture = bottomItem.child as SvgPicture; + checkWidgetProperty( + "runtimeType", + bottomItemSvgPicture.pictureProvider, + bottomItemSvgPicture.pictureProvider.runtimeType, + ExactAssetPicture, + ); + checkWidgetProperty( + "width", + bottomItemSvgPicture, + bottomItemSvgPicture.width, + 27, + ); + + final bottomItemSvgPicturePictureProvider = + bottomItemSvgPicture.pictureProvider as ExactAssetPicture; + checkWidgetProperty( + "assetName", + bottomItemSvgPicturePictureProvider, + bottomItemSvgPicturePictureProvider.assetName, + bottomItems[index], + ); + }); + }); +} diff --git a/clone-instagram-login-Refactoring/test/test_library.dart b/clone-instagram-login-Refactoring/test/test_library.dart new file mode 100644 index 0000000..3f7aae1 --- /dev/null +++ b/clone-instagram-login-Refactoring/test/test_library.dart @@ -0,0 +1,157 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +const String divider = '======================================================'; + +String keyRetriever(String source) { + String key = source; + + int keyIndexBegin = source.indexOf("[<'"); + int keyIndexEnd = source.indexOf("'>]"); + + if (keyIndexBegin != -1 && + keyIndexEnd != -1 && + keyIndexEnd != -1 && + keyIndexEnd > keyIndexBegin + 3) { + key = source.substring(keyIndexBegin + 3, keyIndexEnd); + } + + return key; +} + +void customFlutterErrorHandler(FlutterErrorDetails details) { + if (details.exception is FlutterError && + details.exception.toString().contains('overflow')) { + return; + } + + debugPrint( + 'Terdapat error pada kode program anda\n${details.exceptionAsString()}'); + + FlutterError.presentError(details); + throw details.exception; +} + +void checkError(int index, dynamic expected, dynamic matcher) { + expect(expected, matcher, reason: 'Error at test no. $index'); +} + +// checkByTypeFindOneWidget +void checkByTypeFindOneWidget(Finder finder) { + const String trimString1 = 'zero widgets with type "'; + const String trimString2 = '" (ignoring offstage widgets)'; + + final finderMessage = + finder.toString().replaceAll(trimString1, '').replaceAll(trimString2, ''); + + expect(finder, findsOneWidget, + reason: "Penyebab: Widget $finderMessage Tidak ditemukan\n$divider"); +} + +void checkByTypeFindNWidget(Finder finder, int n) { + expect(finder, findsNWidgets(n), + reason: "Penyebab: Widget $finder Tidak ditemukan\n$divider"); +} + +// checkByKeyFindOneWidget +void checkByKeyFindOneWidget(Finder finder) { + const String trimString1 = "zero widgets with key [<'"; + const String trimString2 = "'>] (ignoring offstage widgets)"; + + final finderMessage = + finder.toString().replaceAll(trimString1, '').replaceAll(trimString2, ''); + + expect(finder, findsOneWidget, + reason: + "Penyebab: Widget dengan key '$finderMessage' tidak ditemukan, pastikan sudah menambahkan key pada widget dan pastikan key pada kode program sesuai dengan guide\n$divider"); +} + +// checkByKeyFindNWidget +void checkByKeyFindNWidget(Finder finder, int n, String reason) { + expect(finder, findsNWidgets(n), reason: reason); +} + +// checkByKeyFindNothing +void checkByKeyFindNothing(Finder finder, String reason) { + expect(finder, findsNothing, reason: reason); +} + +// checkFindTextOneWidget +void checkFindTextOneWidget(String text, String reason) { + expect(find.text(text), findsOneWidget, reason: reason); +} + +// checkFindTextNWidget +void checkFindTextNWidget(String text, int n, String reason) { + expect(find.text(text), findsNWidgets(n), reason: reason); +} + +// checkFindTextNothing +void checkFindTextNothing(String text, String reason) { + expect(find.text(text), findsNothing, reason: reason); +} + +// checkByKeyIsWidget +void checkByKeyIsWidget(dynamic finder, dynamic matcher) { + const matcherString1 = "Instance of 'TypeMatcher<"; + const matcherString2 = ">'"; + final matcherString = matcher + .toString() + .replaceAll(matcherString1, '') + .replaceAll(matcherString2, ''); + + String trimmedFinder = finder.toString(); + + var index = finder.toString().indexOf("-[<"); + if (index != -1) { + trimmedFinder = finder.toString().substring(0, index); + } + + String key = keyRetriever(finder.toString()); + + expect(finder, matcher, + reason: + "Penyebab: Widget yang seharusnya adalah : '$matcherString', namun ditemukan widget dengan tipe: '$trimmedFinder' untuk widget dengan key: '$key'\n$divider"); +} + +// checkWidgetProperty +void checkWidgetProperty(String property, dynamic finderWidget, + dynamic propertyValue, dynamic matcher) { + String key = keyRetriever(finderWidget.toString()); + + expect(propertyValue, matcher, + reason: + "Penyebab: Widget dengan key '$key' seharusnya memiliki properti $property dengan nilai '$matcher', namun nilai yang ditemukan adalah '$propertyValue'\n$divider"); +} + +// checkWidgetDecendantProperty +void checkWidgetDescendantProperty(dynamic parent, dynamic finder) { + String finderKey = keyRetriever(finder.toString()); + String parentKey = keyRetriever(parent.toString()); + expect( + find.descendant(of: parent, matching: finder), + findsOneWidget, + reason: + "Penyebab: Pada widget dengan key '$parentKey' Tidak ditemukan child widget dengan key '$finderKey'", + ); +} + +void checkPreviousTaskIsCompleted( + int index, dynamic expected, dynamic matcher) { + expect(expected, matcher, + reason: 'Task no. $index belum selesai, silahkan cek kembali\n$divider'); +} + +void unfinishedTaskErrorHandler(FlutterErrorDetails details) { + if (details.exception is FlutterError && + details.exception.toString().contains('overflow')) { + return; + } + + debugPrint( + 'Anda belum menyelesaikan task-task sebelumnya, silahkan kerjakan terlebih dahulu sebelum melanjutkan'); + + FlutterError.presentError(details); + throw details.exception; +} diff --git a/clone-instagram-login-Refactoring/web/favicon.png b/clone-instagram-login-Refactoring/web/favicon.png new file mode 100644 index 0000000..8aaa46a Binary files /dev/null and b/clone-instagram-login-Refactoring/web/favicon.png differ diff --git a/clone-instagram-login-Refactoring/web/icons/Icon-192.png b/clone-instagram-login-Refactoring/web/icons/Icon-192.png new file mode 100644 index 0000000..b749bfe Binary files /dev/null and b/clone-instagram-login-Refactoring/web/icons/Icon-192.png differ diff --git a/clone-instagram-login-Refactoring/web/icons/Icon-512.png b/clone-instagram-login-Refactoring/web/icons/Icon-512.png new file mode 100644 index 0000000..88cfd48 Binary files /dev/null and b/clone-instagram-login-Refactoring/web/icons/Icon-512.png differ diff --git a/clone-instagram-login-Refactoring/web/icons/Icon-maskable-192.png b/clone-instagram-login-Refactoring/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..eb9b4d7 Binary files /dev/null and b/clone-instagram-login-Refactoring/web/icons/Icon-maskable-192.png differ diff --git a/clone-instagram-login-Refactoring/web/icons/Icon-maskable-512.png b/clone-instagram-login-Refactoring/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..d69c566 Binary files /dev/null and b/clone-instagram-login-Refactoring/web/icons/Icon-maskable-512.png differ diff --git a/clone-instagram-login-Refactoring/web/index.html b/clone-instagram-login-Refactoring/web/index.html new file mode 100644 index 0000000..386fd27 --- /dev/null +++ b/clone-instagram-login-Refactoring/web/index.html @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + example_widget_testing + + + + + + + + + + diff --git a/clone-instagram-login-Refactoring/web/manifest.json b/clone-instagram-login-Refactoring/web/manifest.json new file mode 100644 index 0000000..b4c7477 --- /dev/null +++ b/clone-instagram-login-Refactoring/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "example_widget_testing", + "short_name": "example_widget_testing", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/clone-instagram-login-Refactoring/windows/.gitignore b/clone-instagram-login-Refactoring/windows/.gitignore new file mode 100644 index 0000000..d492d0d --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/clone-instagram-login-Refactoring/windows/CMakeLists.txt b/clone-instagram-login-Refactoring/windows/CMakeLists.txt new file mode 100644 index 0000000..82b4152 --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/CMakeLists.txt @@ -0,0 +1,101 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(example_widget_testing LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "example_widget_testing") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/clone-instagram-login-Refactoring/windows/flutter/CMakeLists.txt b/clone-instagram-login-Refactoring/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000..930d207 --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/flutter/CMakeLists.txt @@ -0,0 +1,104 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/clone-instagram-login-Refactoring/windows/flutter/generated_plugin_registrant.cc b/clone-instagram-login-Refactoring/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..8b6d468 --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/clone-instagram-login-Refactoring/windows/flutter/generated_plugin_registrant.h b/clone-instagram-login-Refactoring/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..dc139d8 --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/clone-instagram-login-Refactoring/windows/flutter/generated_plugins.cmake b/clone-instagram-login-Refactoring/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000..b93c4c3 --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/clone-instagram-login-Refactoring/windows/runner/CMakeLists.txt b/clone-instagram-login-Refactoring/windows/runner/CMakeLists.txt new file mode 100644 index 0000000..17411a8 --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/runner/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/clone-instagram-login-Refactoring/windows/runner/Runner.rc b/clone-instagram-login-Refactoring/windows/runner/Runner.rc new file mode 100644 index 0000000..9ea8d1e --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "example_widget_testing" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "example_widget_testing" "\0" + VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "example_widget_testing.exe" "\0" + VALUE "ProductName", "example_widget_testing" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/clone-instagram-login-Refactoring/windows/runner/flutter_window.cpp b/clone-instagram-login-Refactoring/windows/runner/flutter_window.cpp new file mode 100644 index 0000000..b43b909 --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/runner/flutter_window.cpp @@ -0,0 +1,61 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/clone-instagram-login-Refactoring/windows/runner/flutter_window.h b/clone-instagram-login-Refactoring/windows/runner/flutter_window.h new file mode 100644 index 0000000..6da0652 --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/clone-instagram-login-Refactoring/windows/runner/main.cpp b/clone-instagram-login-Refactoring/windows/runner/main.cpp new file mode 100644 index 0000000..c099f0e --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.CreateAndShow(L"example_widget_testing", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/clone-instagram-login-Refactoring/windows/runner/resource.h b/clone-instagram-login-Refactoring/windows/runner/resource.h new file mode 100644 index 0000000..66a65d1 --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/clone-instagram-login-Refactoring/windows/runner/resources/app_icon.ico b/clone-instagram-login-Refactoring/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000..c04e20c Binary files /dev/null and b/clone-instagram-login-Refactoring/windows/runner/resources/app_icon.ico differ diff --git a/clone-instagram-login-Refactoring/windows/runner/runner.exe.manifest b/clone-instagram-login-Refactoring/windows/runner/runner.exe.manifest new file mode 100644 index 0000000..a42ea76 --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/clone-instagram-login-Refactoring/windows/runner/utils.cpp b/clone-instagram-login-Refactoring/windows/runner/utils.cpp new file mode 100644 index 0000000..f5bf9fa --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/runner/utils.cpp @@ -0,0 +1,64 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, utf8_string.data(), + target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/clone-instagram-login-Refactoring/windows/runner/utils.h b/clone-instagram-login-Refactoring/windows/runner/utils.h new file mode 100644 index 0000000..3879d54 --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/clone-instagram-login-Refactoring/windows/runner/win32_window.cpp b/clone-instagram-login-Refactoring/windows/runner/win32_window.cpp new file mode 100644 index 0000000..c10f08d --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/runner/win32_window.cpp @@ -0,0 +1,245 @@ +#include "win32_window.h" + +#include + +#include "resource.h" + +namespace { + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + FreeLibrary(user32_module); + } +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::CreateAndShow(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + return OnCreate(); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} diff --git a/clone-instagram-login-Refactoring/windows/runner/win32_window.h b/clone-instagram-login-Refactoring/windows/runner/win32_window.h new file mode 100644 index 0000000..17ba431 --- /dev/null +++ b/clone-instagram-login-Refactoring/windows/runner/win32_window.h @@ -0,0 +1,98 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates and shows a win32 window with |title| and position and size using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size to will treat the width height passed in to this function + // as logical pixels and scale to appropriate for the default monitor. Returns + // true if the window was created successfully. + bool CreateAndShow(const std::wstring& title, + const Point& origin, + const Size& size); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responsponds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/test/account_page_test.dart b/test/account_page_test.dart new file mode 100644 index 0000000..c3ce248 --- /dev/null +++ b/test/account_page_test.dart @@ -0,0 +1,2128 @@ +import 'package:example_widget_testing/app/data/models/profile.dart'; +import 'package:example_widget_testing/app/modules/account/account_page.dart'; +import 'package:example_widget_testing/app/modules/account/components/account_name.dart'; +import 'package:example_widget_testing/app/modules/account/components/account_stat.dart'; +import 'package:example_widget_testing/app/modules/account/components/account_tab.dart'; +import 'package:example_widget_testing/app/modules/account/components/grey_button.dart'; +import 'package:example_widget_testing/app/modules/account/components/highlight_item.dart'; +import 'package:example_widget_testing/app/modules/account/components/highlight_list.dart'; +import 'package:example_widget_testing/app/modules/account/components/profile_buttons.dart'; +import 'package:example_widget_testing/app/modules/account/components/profile_information.dart'; +import 'package:example_widget_testing/app/modules/account/components/profile_pic.dart'; +import 'package:example_widget_testing/app/widgets/post_thumbnail.dart'; +import 'package:example_widget_testing/core/values/constant/post_json.dart'; +import 'package:example_widget_testing/core/values/constant/profile_json.dart'; +import 'package:example_widget_testing/core/values/constant/profile_tabs_json.dart'; +import 'package:example_widget_testing/core/values/constant/story_json.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network_image_mock/network_image_mock.dart'; + +import 'helper.dart'; + +bool checkError(int index, dynamic expected, dynamic matcher) { + if (expected == null) { + debugPrint('Account Page Test-$index failed: expected is null'); + return false; + } + try { + expect(expected, matcher); + } catch (e) { + debugPrint('Account Page Test-$index failed:'); + debugPrint(e.toString()); + return false; + } + return true; +} + +final Profile profile = Profile.fromJson(profileJson); + +void main() { + final states = {}; + testWidgets('Check if Account page Appbar is present', + (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: AccountPage( + posts: posts, + stories: stories, + profileData: profileJson, + ), + ), + ), + ); + + final appBarFinder = find.byKey(const Key('app_bar_account')); + checkError(2, appBarFinder, findsOneWidget); + + final appBar = appBarFinder.evaluate().first.widget as AppBar; + checkError(3, appBar.backgroundColor, Colors.black); + checkError(4, appBar.automaticallyImplyLeading, false); + final appBarRowFinder = find.byKey(const Key('app_bar_row')); + if (checkError(5, appBarRowFinder, findsOneWidget)) { + final appBarRow = appBarRowFinder.evaluate().first.widget as Row; + checkError( + 6, appBarRow.mainAxisAlignment, MainAxisAlignment.spaceBetween); + checkError(7, appBarRow.children.length, 2); + + final appBarRowNameFinder = find.byKey(const Key('app_bar_row_name')); + if (checkError( + 8, + find.descendant(of: appBarRowFinder, matching: appBarRowNameFinder), + findsOneWidget, + )) { + final appBarRowName = + appBarRowNameFinder.evaluate().first.widget as Row; + checkError(9, appBarRowName.children.length, 2); + + final appBarRowNameTextFinder = + find.byKey(const Key('app_bar_row_name_text')); + if (checkError( + 10, + find.descendant( + of: appBarRowNameFinder, matching: appBarRowNameTextFinder), + findsOneWidget)) { + final appBarRowNameText = + appBarRowNameTextFinder.evaluate().first.widget as Text; + checkError(11, appBarRowNameText.data, 'iclop'); + checkError(12, appBarRowNameText.style!.fontWeight, FontWeight.bold); + + final appBarRowNameArrowDownIconFinder = + find.byKey(const Key('app_bar_row_name_arrow_down_icon')); + if (checkError( + 13, + find.descendant( + of: appBarRowNameFinder, + matching: appBarRowNameArrowDownIconFinder), + findsOneWidget)) { + final appBarRowNameArrowDownIcon = appBarRowNameArrowDownIconFinder + .evaluate() + .first + .widget as Icon; + checkError( + 14, appBarRowNameArrowDownIcon.icon, Icons.keyboard_arrow_down); + } + } + } + + final appBarRowMenuFinder = find.byKey(const Key('app_bar_row_menu')); + bool appBarRowMenuIsAvailable = checkError( + 15, + find.descendant(of: appBarRowFinder, matching: appBarRowMenuFinder), + findsOneWidget); + if (appBarRowMenuIsAvailable) { + final appBarRowMenu = + appBarRowMenuFinder.evaluate().first.widget as Row; + checkError(16, appBarRowMenu.children.length, 3); + + final appBarRowMenuUploadIconFinder = + find.byKey(const Key('app_bar_row_menu_upload_icon')); + bool appBarRowMenuUploadIconIsAvailable = checkError( + 17, + find.descendant( + of: appBarRowMenuFinder, + matching: appBarRowMenuUploadIconFinder), + findsOneWidget); + bool appBarRowMenuUploadIconIsSvgPicture = checkError( + 18, + appBarRowMenuUploadIconFinder.evaluate().first.widget, + isA()); + if (appBarRowMenuUploadIconIsAvailable && + appBarRowMenuUploadIconIsSvgPicture) { + final appBarRowMenuUploadIcon = appBarRowMenuUploadIconFinder + .evaluate() + .first + .widget as SvgPicture; + checkError(19, appBarRowMenuUploadIcon.width, 27); + bool appBarRowMenuUploadIconIsAssetPicture = checkError( + 20, + appBarRowMenuUploadIcon.pictureProvider.runtimeType, + ExactAssetPicture); + if (appBarRowMenuUploadIconIsAssetPicture) { + final appBarRowMenuUploadIconAssetPicture = + appBarRowMenuUploadIcon.pictureProvider as ExactAssetPicture; + checkError(21, appBarRowMenuUploadIconAssetPicture.assetName, + "assets/images/upload_icon.svg"); + } + } + + final appBarRowMenuHamburgerIconFinder = + find.byKey(const Key('app_bar_row_menu_hamburger_icon')); + bool appBarRowMenuHamburgerIconIsAvailable = checkError( + 22, + find.descendant( + of: appBarRowMenuFinder, + matching: appBarRowMenuHamburgerIconFinder), + findsOneWidget); + bool appBarRowMenuHamburgerIconIsIcon = checkError( + 23, + appBarRowMenuHamburgerIconFinder.evaluate().first.widget, + isA()); + if (appBarRowMenuHamburgerIconIsAvailable && + appBarRowMenuHamburgerIconIsIcon) { + final appBarRowMenuHamburgerIcon = + appBarRowMenuHamburgerIconFinder.evaluate().first.widget as Icon; + checkError(24, appBarRowMenuHamburgerIcon.size, 35); + checkError(25, appBarRowMenuHamburgerIcon.icon, Icons.menu); + } + } + } + }); + testWidgets("Check if Account page body is present", (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: AccountPage( + posts: posts, + stories: stories, + profileData: profileJson, + ), + ), + ), + ); + + final accountPageListViewFinder = find.byKey( + const Key('account_page_listview'), + ); + checkError(26, accountPageListViewFinder, findsOneWidget); + + final accountStatFinder = find.byKey(const Key('account_stat')); + checkError(27, accountStatFinder, findsOneWidget); + + final accountNameFinder = find.byKey(const Key('account_name')); + checkError(28, accountNameFinder, findsOneWidget); + + final profileButtons = find.byKey(const Key('profile_buttons')); + checkError(29, profileButtons, findsOneWidget); + + final highlightList = find.byKey(const Key('highlight_list')); + checkError(30, highlightList, findsOneWidget); + + final accountTab = find.byKey(const Key('account_tab')); + checkError(31, accountTab, findsOneWidget); + + final accountPagePostWrapFinder = + find.byKey(const Key('account_page_post_wrap')); + bool isAccountPagePostWrapAvailable = checkError( + 32, + accountPagePostWrapFinder, + findsOneWidget, + ); + if (isAccountPagePostWrapAvailable) { + final accountPagePostWrap = + accountPagePostWrapFinder.evaluate().first.widget as Wrap; + checkError(33, accountPagePostWrap.spacing, 1.5); + checkError(34, accountPagePostWrap.runSpacing, 1.5); + checkError(35, accountPagePostWrap.children.length, posts.length); + posts.asMap().forEach((key, value) { + final accountPostInkWellFinder = find.byKey( + Key('account_post_inkwell_$key'), + ); + bool isAccountPostInkWellAvailable = checkError( + 351, + accountPostInkWellFinder, + findsOneWidget, + ); + if (isAccountPostInkWellAvailable) { + checkError( + 352, + accountPostInkWellFinder.evaluate().first.widget, + isA(), + ); + final accountPostThumbnailFinder = find.byKey( + Key('account_post_thumbnail_$key'), + ); + bool isAccountPostThumbnailAvailable = checkError( + 353, + accountPostThumbnailFinder, + findsOneWidget, + ); + if (isAccountPostThumbnailAvailable) { + bool accountPostThumbnailIsPostThumbnail = checkError( + 354, + accountPostThumbnailFinder.evaluate().first.widget, + isA(), + ); + if (accountPostThumbnailIsPostThumbnail) { + final accountPostThumbnail = accountPostThumbnailFinder + .evaluate() + .first + .widget as PostThumbnail; + checkError( + 355, + accountPostThumbnail.imageUrl, + posts[key]['postImg'], + ); + } + } + } + }); + } + }); + testWidgets("Check if account stats is present", (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: AccountStat(profile: profile), + ), + ), + ); + + final accountPageProfileRowFinder = + find.byKey(const Key('account_page_profile_row')); + bool accounntPageListViewIsAvailable = checkError( + 26, + accountPageProfileRowFinder, + findsOneWidget, + ); + bool accounntPageListViewIsRow = checkError( + 27, + accountPageProfileRowFinder.evaluate().first.widget, + isA(), + ); + if (accounntPageListViewIsAvailable && accounntPageListViewIsRow) { + final accountPageProfileRow = + accountPageProfileRowFinder.evaluate().first.widget as Row; + checkError(28, accountPageProfileRow.children.length, 2); + + final profilePicFinder = find.byKey(const Key('profile_pic')); + checkError(29, profilePicFinder, findsOneWidget); + + final accountPageProfileInformationExpandedFinder = find.byKey( + const Key('account_page_profile_information_expanded'), + ); + bool accountPageProfileInformationExpandedIsAvailable = checkError( + 30, + accountPageProfileInformationExpandedFinder, + findsOneWidget, + ); + + checkError( + 31, + accountPageProfileInformationExpandedFinder.evaluate().first.widget, + isA(), + ); + + if (accountPageProfileInformationExpandedIsAvailable) { + final profileInformationFinder = find.byKey( + const Key('profile_information'), + ); + checkError( + 32, + find.descendant( + of: accountPageProfileInformationExpandedFinder, + matching: profileInformationFinder, + ), + findsOneWidget, + ); + } + } + }); + testWidgets("Check if profile picture is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: ProfilePic(pictureUrl: profile.profilePic!), + ), + ), + ); + + final profilePicContainerFinder = find.byKey( + const Key('profile_pic_container'), + ); + bool profilePicContainerIsAvailable = checkError( + 33, + profilePicContainerFinder, + findsOneWidget, + ); + if (profilePicContainerIsAvailable) { + bool profilePicContainerIsContainer = checkError( + 34, + profilePicContainerFinder.evaluate().first.widget, + isA(), + ); + if (profilePicContainerIsContainer) { + final profilePicContainer = + profilePicContainerFinder.evaluate().first.widget as Container; + checkError( + 35, + profilePicContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 80, maxWidth: 80), + ); + checkError( + 36, + profilePicContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 80, maxHeight: 80), + ); + checkError( + 37, + profilePicContainer.margin, + const EdgeInsets.only(left: 15, right: 30), + ); + final profilePicDecoration = + profilePicContainer.decoration as BoxDecoration; + bool profilePicDecorationIsBoxDecoration = checkError( + 38, + profilePicDecoration, + isA(), + ); + + if (profilePicDecorationIsBoxDecoration) { + final profilePicDecoration = + profilePicContainer.decoration as BoxDecoration; + checkError( + 39, + profilePicDecoration.shape, + BoxShape.circle, + ); + + bool profilePicDecorationImageIsDecorationImage = checkError( + 40, + profilePicDecoration.image, + isA(), + ); + if (profilePicDecorationImageIsDecorationImage) { + final profilePicDecorationImage = + profilePicDecoration.image as DecorationImage; + checkError(41, profilePicDecorationImage.fit, BoxFit.cover); + bool profilePicDecorationImageIsNetworkImage = checkError( + 42, + profilePicDecorationImage.image, + isA(), + ); + if (profilePicDecorationImageIsNetworkImage) { + final profilePicDecorationImageNetworkImage = + profilePicDecorationImage.image as NetworkImage; + checkError( + 43, + profilePicDecorationImageNetworkImage.url, + profile.profilePic!, + ); + } + } + } + } + } + }); + testWidgets("Check if profile informations is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: ProfileInformation(profileStats: profile.stats!), + ), + ), + ); + + final profileInformationRowFinder = find.byKey( + const Key('profile_information_row'), + ); + bool profileInformationRowIsAvailable = checkError( + 44, + profileInformationRowFinder, + findsOneWidget, + ); + if (profileInformationRowIsAvailable) { + bool profileInformationRowIsRow = checkError( + 45, profileInformationRowFinder.evaluate().first.widget, isA()); + if (profileInformationRowIsRow) { + final profileInformationRow = + profileInformationRowFinder.evaluate().first.widget as Row; + checkError( + 46, profileInformationRow.children.length, profile.stats!.length); + checkError( + 47, + profileInformationRow.mainAxisAlignment, + MainAxisAlignment.spaceAround, + ); + + profile.stats!.asMap().forEach((index, value) { + final profileInformationColumnFinder = find.byKey( + Key('profile_information_column_$index'), + ); + bool profileInformationColumnIsAvailable = checkError( + 48, + profileInformationColumnFinder, + findsOneWidget, + ); + if (profileInformationColumnIsAvailable) { + bool profileInformationColumnIsColumn = checkError( + 49, + profileInformationColumnFinder.evaluate().first.widget, + isA(), + ); + if (profileInformationColumnIsColumn) { + final profileInformationColumn = profileInformationColumnFinder + .evaluate() + .first + .widget as Column; + checkError(50, profileInformationColumn.children.length, 2); + + final profileInformationAmountTextFinder = find.byKey( + Key('profile_information_${index}_amount_text'), + ); + bool profileInformationAmountTextIsAvailable = checkError( + 51, + profileInformationAmountTextFinder, + findsOneWidget, + ); + if (profileInformationAmountTextIsAvailable) { + bool profileInformationAmountTextIsText = checkError( + 52, + profileInformationAmountTextFinder.evaluate().first.widget, + isA(), + ); + if (profileInformationAmountTextIsText) { + final profileInformationAmountText = + profileInformationAmountTextFinder.evaluate().first.widget + as Text; + checkError(53, profileInformationAmountText.data, + profile.stats![index].count.toString()); + checkError( + 54, + profileInformationAmountText.style, + const TextStyle( + fontSize: 20, + fontWeight: FontWeight.w700, + color: Colors.white), + ); + } + } + + final profileInformationLabelTextFinder = find.byKey( + Key('profile_information_${index}_label_text'), + ); + bool profileInformationLabelTextIsAvailable = checkError( + 55, + profileInformationLabelTextFinder, + findsOneWidget, + ); + if (profileInformationLabelTextIsAvailable) { + bool profileInformationLabelTextIsText = checkError( + 56, + profileInformationLabelTextFinder.evaluate().first.widget, + isA(), + ); + if (profileInformationLabelTextIsText) { + final profileInformationLabelText = + profileInformationLabelTextFinder.evaluate().first.widget + as Text; + checkError(57, profileInformationLabelText.data, + profile.stats![index].label); + checkError( + 58, + profileInformationLabelText.style, + const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w400, + color: Colors.white, + ), + ); + } + } + } + } + }); + } + } + }); + testWidgets("Check if account's name is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: AccountName(profile: profile), + ), + ), + ); + + final accountNameContainerFinder = find.byKey( + const Key('account_name_container'), + ); + bool accountNameContainerIsAvailable = checkError( + 59, + accountNameContainerFinder, + findsOneWidget, + ); + if (accountNameContainerIsAvailable) { + bool accountNameContainerIsContainer = checkError( + 60, + accountNameContainerFinder.evaluate().first.widget, + isA(), + ); + if (accountNameContainerIsContainer) { + final accountNameContainer = + accountNameContainerFinder.evaluate().first.widget as Container; + checkError( + 61, + accountNameContainer.constraints!.widthConstraints(), + const BoxConstraints( + minWidth: double.infinity, maxWidth: double.infinity), + ); + checkError( + 62, + accountNameContainer.padding, + const EdgeInsets.symmetric(horizontal: 15), + ); + checkError( + 63, + accountNameContainer.margin, + const EdgeInsets.symmetric(vertical: 10), + ); + + final accountNameColumnFinder = find.byKey( + const Key('account_name_column'), + ); + bool accountNameColumnIsAvailable = checkError( + 64, + find.descendant( + of: accountNameContainerFinder, + matching: accountNameColumnFinder), + findsOneWidget, + ); + + if (accountNameColumnIsAvailable) { + bool accountNameColumnIsColumn = checkError( + 65, + accountNameColumnFinder.evaluate().first.widget, + isA(), + ); + + if (accountNameColumnIsColumn) { + final accountNameColumn = + accountNameColumnFinder.evaluate().first.widget as Column; + checkError( + 66, + accountNameColumn.crossAxisAlignment, + CrossAxisAlignment.start, + ); + checkError(67, accountNameColumn.children.length, 2); + + final accountNameTextFinder = find.byKey( + const Key('account_name_text'), + ); + + bool accountNameTextIsAvailable = checkError( + 68, + find.descendant( + of: accountNameColumnFinder, matching: accountNameTextFinder), + findsOneWidget, + ); + + if (accountNameTextIsAvailable) { + bool accountNameTextIsText = checkError( + 69, + accountNameTextFinder.evaluate().first.widget, + isA(), + ); + + if (accountNameTextIsText) { + final accountNameText = + accountNameTextFinder.evaluate().first.widget as Text; + checkError(70, accountNameText.data, profile.name); + checkError( + 71, + accountNameText.style, + const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w400, + color: Colors.white, + ), + ); + } + } + + final accountBioText = find.byKey(const Key('account_bio_text')); + bool accountBioTextIsAvailable = checkError( + 72, + find.descendant( + of: accountNameColumnFinder, matching: accountBioText), + findsOneWidget, + ); + + if (accountBioTextIsAvailable) { + bool accountBioTextIsText = checkError( + 73, + accountBioText.evaluate().first.widget, + isA(), + ); + + if (accountBioTextIsText) { + final accountBioTextWidget = + accountBioText.evaluate().first.widget as Text; + checkError(74, accountBioTextWidget.data, profile.bio); + checkError( + 75, + accountBioTextWidget.style, + const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w400, + color: Colors.white, + ), + ); + } + } + } + } + } + } + }); + testWidgets("Check if profile buttons is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + const MaterialApp( + home: ProfileButtons(), + ), + ), + ); + + final profileButtonsPaddingFinder = find.byKey( + const Key('profile_buttons_padding'), + ); + + bool accountPageProfileButtonsPaddingIsAvailable = checkError( + 76, + profileButtonsPaddingFinder, + findsOneWidget, + ); + + if (accountPageProfileButtonsPaddingIsAvailable) { + bool accountPageProfileButtonsPaddingIsPadding = checkError( + 77, + profileButtonsPaddingFinder.evaluate().first.widget, + isA(), + ); + + if (accountPageProfileButtonsPaddingIsPadding) { + final accountPageProfileButtonsPadding = + profileButtonsPaddingFinder.evaluate().first.widget as Padding; + checkError( + 78, + accountPageProfileButtonsPadding.padding, + const EdgeInsets.symmetric(horizontal: 15), + ); + + final profileButtonsRowFinder = + find.byKey(const Key('profile_buttons_row')); + bool profileButtonsRowIsAvailable = checkError( + 79, + find.descendant( + of: profileButtonsPaddingFinder, + matching: profileButtonsRowFinder), + findsOneWidget, + ); + + if (profileButtonsRowIsAvailable) { + bool profileButtonsRowIsRow = checkError( + 80, + profileButtonsRowFinder.evaluate().first.widget, + isA(), + ); + + if (profileButtonsRowIsRow) { + final profileButtonsRow = + profileButtonsRowFinder.evaluate().first.widget as Row; + checkError( + 81, + profileButtonsRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween, + ); + checkError(82, profileButtonsRow.children.length, 5); + + final profileButtonsEditProfileButtonExpandedFinder = find.byKey( + const Key('profile_buttons_edit_profile_button_expanded'), + ); + bool profileButtonsEditProfileButtonExpandedIsAvailable = + checkError( + 83, + find.descendant( + of: profileButtonsRowFinder, + matching: profileButtonsEditProfileButtonExpandedFinder, + ), + findsOneWidget, + ); + + if (profileButtonsEditProfileButtonExpandedIsAvailable) { + checkError( + 84, + profileButtonsEditProfileButtonExpandedFinder + .evaluate() + .first + .widget, + isA(), + ); + + final profileButtonsEditProfileButtonFinder = find.byKey( + const Key('profile_buttons_edit_profile_button'), + ); + bool profileButtonsEditProfileButtonIsAvailable = checkError( + 85, + find.descendant( + of: profileButtonsEditProfileButtonExpandedFinder, + matching: profileButtonsEditProfileButtonFinder), + findsOneWidget, + ); + if (profileButtonsEditProfileButtonIsAvailable) { + checkError( + 86, + profileButtonsEditProfileButtonFinder.evaluate().first.widget, + isA(), + ); + + final profileButtonsEditProfileButtonTextFinder = find.byKey( + const Key('profile_buttons_edit_profile_button_text'), + ); + bool profileButtonsEditProfileButtonTextIsAvailable = + checkError( + 87, + find.descendant( + of: profileButtonsEditProfileButtonFinder, + matching: profileButtonsEditProfileButtonTextFinder), + findsOneWidget, + ); + if (profileButtonsEditProfileButtonTextIsAvailable) { + bool profileButtonsEditProfileButtonTextIsText = checkError( + 88, + profileButtonsEditProfileButtonTextFinder + .evaluate() + .first + .widget, + isA(), + ); + if (profileButtonsEditProfileButtonTextIsText) { + final profileButtonsEditProfileButtonText = + profileButtonsEditProfileButtonTextFinder + .evaluate() + .first + .widget as Text; + checkError( + 89, + profileButtonsEditProfileButtonText.data, + 'Edit Profile', + ); + checkError( + 90, + profileButtonsEditProfileButtonText.style, + const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + ); + } + } + } + } + + final profileButtonsShareProfileButtonExpandedFinder = find.byKey( + const Key('profile_buttons_share_profile_button_expanded'), + ); + bool profileButtonsShareProfileButtonExpandedIsAvailable = + checkError( + 91, + find.descendant( + of: profileButtonsRowFinder, + matching: profileButtonsShareProfileButtonExpandedFinder, + ), + findsOneWidget, + ); + if (profileButtonsShareProfileButtonExpandedIsAvailable) { + checkError( + 92, + profileButtonsShareProfileButtonExpandedFinder + .evaluate() + .first + .widget, + isA(), + ); + + final profileButtonsShareProfileButtonFinder = find.byKey( + const Key('profile_buttons_share_profile_button'), + ); + bool profileButtonsShareProfileButtonIsAvailable = checkError( + 93, + find.descendant( + of: profileButtonsShareProfileButtonExpandedFinder, + matching: profileButtonsShareProfileButtonFinder), + findsOneWidget, + ); + if (profileButtonsShareProfileButtonIsAvailable) { + checkError( + 94, + profileButtonsShareProfileButtonFinder + .evaluate() + .first + .widget, + isA(), + ); + + final profileButtonsShareProfileButtonTextFinder = find.byKey( + const Key('profile_buttons_share_profile_button_text'), + ); + bool profileButtonsShareProfileButtonTextIsAvailable = + checkError( + 95, + find.descendant( + of: profileButtonsShareProfileButtonFinder, + matching: profileButtonsShareProfileButtonTextFinder), + findsOneWidget, + ); + if (profileButtonsShareProfileButtonTextIsAvailable) { + bool profileButtonsShareProfileButtonTextIsText = checkError( + 96, + profileButtonsShareProfileButtonTextFinder + .evaluate() + .first + .widget, + isA(), + ); + if (profileButtonsShareProfileButtonTextIsText) { + final profileButtonsShareProfileButtonText = + profileButtonsShareProfileButtonTextFinder + .evaluate() + .first + .widget as Text; + checkError( + 97, + profileButtonsShareProfileButtonText.data, + 'Share profile', + ); + checkError( + 98, + profileButtonsShareProfileButtonText.style, + const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + ); + } + } + } + } + + final profileButtonsDiscoverPeopleButtonFinder = find.byKey( + const Key('profile_buttons_discover_people_button'), + ); + bool profileButtonsDiscoverPeopleButtonIsAvailable = checkError( + 99, + find.descendant( + of: profileButtonsRowFinder, + matching: profileButtonsDiscoverPeopleButtonFinder), + findsOneWidget, + ); + if (profileButtonsDiscoverPeopleButtonIsAvailable) { + checkError( + 100, + profileButtonsDiscoverPeopleButtonFinder + .evaluate() + .first + .widget, + isA(), + ); + + final profileButtonsDiscoverPeopleIconFinder = find.byKey( + const Key('profile_buttons_discover_people_icon'), + ); + bool profileButtonsDiscoverPeopleIconIsAvailable = checkError( + 101, + find.descendant( + of: profileButtonsDiscoverPeopleButtonFinder, + matching: profileButtonsDiscoverPeopleIconFinder), + findsOneWidget, + ); + if (profileButtonsDiscoverPeopleIconIsAvailable) { + bool profileButtonsDiscoverPeopleIconIsIcon = checkError( + 102, + profileButtonsDiscoverPeopleIconFinder + .evaluate() + .first + .widget, + isA(), + ); + if (profileButtonsDiscoverPeopleIconIsIcon) { + final profileButtonsDiscoverPeopleIcon = + profileButtonsDiscoverPeopleIconFinder + .evaluate() + .first + .widget as Icon; + checkError( + 103, + profileButtonsDiscoverPeopleIcon.icon, + Icons.person_add_outlined, + ); + checkError( + 104, + profileButtonsDiscoverPeopleIcon.color, + Colors.white, + ); + } + } + } + } + } + } + } + }); + testWidgets("Check if Grey buttons is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + const mockKey = Key('grey_button'); + const mockWidget = Text('Grey Button'); + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: GreyButton( + key: mockKey, + onPressed: () {}, + child: mockWidget, + ), + ), + ), + ); + + final greyButtonElevatedButtonFinder = find.byKey( + Key('${mockKey}_elevated_button'), + ); + bool greyButtonElevatedButtonIsAvailable = checkError( + 105, + greyButtonElevatedButtonFinder, + findsOneWidget, + ); + if (greyButtonElevatedButtonIsAvailable) { + bool greyButtonElevatedButtonIsElevatedButton = checkError( + 106, + greyButtonElevatedButtonFinder.evaluate().first.widget, + isA(), + ); + if (greyButtonElevatedButtonIsElevatedButton) { + final greyButtonElevatedButton = greyButtonElevatedButtonFinder + .evaluate() + .first + .widget as ElevatedButton; + try { + checkError( + 107, + greyButtonElevatedButton.style!.backgroundColor!.resolve(states), + Colors.grey[800], + ); + } catch (e) { + debugPrint( + "Account Page Test-107 failed: backgroundColor is not set", + ); + } + + try { + checkError( + 108, + greyButtonElevatedButton.style!.minimumSize!.resolve(states), + const Size(0, 30), + ); + } catch (e) { + debugPrint( + "Account Page Test-108 failed: minimumSize is not set", + ); + } + + try { + checkError( + 109, + greyButtonElevatedButton.style!.shape!.resolve(states), + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5), + ), + ); + } catch (e) { + debugPrint( + "Account Page Test-109 failed: shape is not set", + ); + } + } + } + }); + testWidgets("Check if Highlight list is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: HighlightList(stories: stories), + ), + ), + ); + + final highlightListScrollViewFinder = find.byKey( + const Key('highlight_list_scroll_view'), + ); + + bool highlightListScrollViewIsAvailable = checkError( + 110, + highlightListScrollViewFinder, + findsOneWidget, + ); + + if (highlightListScrollViewIsAvailable) { + bool highlightListScrollViewIsScrollView = checkError( + 111, + highlightListScrollViewFinder.evaluate().first.widget, + isA(), + ); + if (highlightListScrollViewIsScrollView) { + final highlightListScrollView = highlightListScrollViewFinder + .evaluate() + .first + .widget as SingleChildScrollView; + checkError( + 112, + highlightListScrollView.scrollDirection, + Axis.horizontal, + ); + checkError( + 113, + highlightListScrollView.padding, + const EdgeInsets.only(left: 15, top: 10, bottom: 10), + ); + } + final highlightListParentRowFinder = find.byKey( + const Key("highlight_list_parent_row"), + ); + bool highlightListParentRowIsAvailable = checkError( + 114, + find.descendant( + of: highlightListScrollViewFinder, + matching: highlightListParentRowFinder, + ), + findsOneWidget, + ); + if (highlightListParentRowIsAvailable) { + checkError( + 115, + highlightListParentRowFinder.evaluate().first.widget, + isA(), + ); + final highlightListChildRowFinder = find.byKey( + const Key("highlight_list_child_row"), + ); + bool highlightListChildRowIsAvailable = checkError( + 116, + find.descendant( + of: highlightListParentRowFinder, + matching: highlightListChildRowFinder, + ), + findsOneWidget, + ); + if (highlightListChildRowIsAvailable) { + bool highlightListChildRowIsRow = checkError( + 117, + highlightListChildRowFinder.evaluate().first.widget, + isA(), + ); + if (highlightListChildRowIsRow) { + final highlightListChildRow = + highlightListChildRowFinder.evaluate().first.widget as Row; + bool highlightItemsFinder = checkError( + 118, + highlightListChildRow.children.length, + stories.length, + ); + + if (highlightItemsFinder) { + stories.asMap().forEach((key, value) { + final highlightItemFinder = find.byKey( + Key("highlight_item_$key"), + ); + bool highlightItemIsAvailable = checkError( + 119, + find.descendant( + of: highlightListChildRowFinder, + matching: highlightItemFinder, + ), + findsOneWidget, + ); + + if (highlightItemIsAvailable) { + bool highlightItemIsHighlightItem = checkError( + 120, + highlightItemFinder.evaluate().first.widget, + isA(), + ); + if (highlightItemIsHighlightItem) { + final highlightItem = highlightItemFinder + .evaluate() + .first + .widget as HighlightItem; + checkError( + 121, + highlightItem.img, + value["img"], + ); + checkError( + 122, + highlightItem.name, + value["name"], + ); + } + } + }); + } + } + } + + final highightListAddHighlightFinder = find.byKey( + const Key("highlight_list_add_highlight"), + ); + bool highightAddHighlightIsAvailable = checkError( + 123, + find.descendant( + of: highlightListParentRowFinder, + matching: highightListAddHighlightFinder, + ), + findsOneWidget, + ); + + if (highightAddHighlightIsAvailable) { + bool highightAddHighlightIsPadding = checkError( + 124, + highightListAddHighlightFinder.evaluate().first.widget, + isA(), + ); + if (highightAddHighlightIsPadding) { + final highightAddHighlight = highightListAddHighlightFinder + .evaluate() + .first + .widget as Padding; + checkError( + 125, + highightAddHighlight.padding, + const EdgeInsets.only(right: 10, bottom: 10), + ); + } + + final highlightListAddHighlightColumnFinder = find.byKey( + const Key("highlight_list_add_highlight_column"), + ); + bool highlightListAddHighlightColumnIsAvailable = checkError( + 126, + find.descendant( + of: highightListAddHighlightFinder, + matching: highlightListAddHighlightColumnFinder, + ), + findsOneWidget, + ); + if (highlightListAddHighlightColumnIsAvailable) { + bool highlightListAddHighlightColumnIsColumn = checkError( + 127, + highlightListAddHighlightColumnFinder.evaluate().first.widget, + isA(), + ); + if (highlightListAddHighlightColumnIsColumn) { + final highlightListAddHighlightColumn = + highlightListAddHighlightColumnFinder.evaluate().first.widget + as Column; + checkError( + 129, + highlightListAddHighlightColumn.children.length, + 2, + ); + // final highlightListAddHighlightIconFinder = find.byKey( + // const Key("highlight_list_add_highlight_icon"), + // ); + // bool highlightListAddHighlightIconIsAvailable = checkError( + // 130, + // find.descendant( + // of: highlightListAddHighlightColumnFinder, + // matching: highlightListAddHighlightIconFinder, + // ), + // findsOneWidget, + // ); + // if (highlightListAddHighlightIconIsAvailable) { + // bool highlightListAddHighlightIconIsIcon = checkError( + // 131, + // highlightListAddHighlightIconFinder.evaluate().first.widget, + // isA(), + // ); + // if (highlightListAddHighlightIconIsIcon) { + // final highlightListAddHighlightIcon = + // highlightListAddHighlightIconFinder + // .evaluate() + // .first + // .widget as Icon; + // checkError( + // 132, + // highlightListAddHighlightIcon.icon, + // Icons.add, + // ); + // checkError( + // 133, + // highlightListAddHighlightIcon.color, + // Colors.white, + // ); + // } + // } + // final highlightListAddHighlightTextFinder = find.byKey( + // const Key("highlight_list_add_highlight_text"), + // ); + // bool highlightListAddHighlightTextIsAvailable = checkError( + // 134, + // find.descendant( + // of: highlightListAddHighlightColumnFinder, + // matching: highlightListAddHighlightTextFinder, + // ), + // findsOneWidget, + // ); + // if (highlightListAddHighlightTextIsAvailable) { + // bool highlightListAddHighlightTextIsText = checkError( + // 135, + // highlightListAddHighlightTextFinder.evaluate().first.widget, + // isA(), + // ); + // if (highlightListAddHighlightTextIsText) { + // final highlightListAddHighlightText = + // highlightListAddHighlightTextFinder + // .evaluate() + // .first + // .widget as Text; + // checkError( + // 136, + // highlightListAddHighlightText.data, + // "New", + // ); + // } + // } + } + + final highlightListAddHighlightContainerFinder = find.byKey( + const Key("highlight_list_add_highlight_container"), + ); + bool highlightAddHighlightContainerIsAvailable = checkError( + 137, + find.descendant( + of: highlightListAddHighlightColumnFinder, + matching: highlightListAddHighlightContainerFinder, + ), + findsOneWidget, + ); + if (highlightAddHighlightContainerIsAvailable) { + bool highlightAddHighlightContainerIsContainer = checkError( + 138, + highlightListAddHighlightContainerFinder + .evaluate() + .first + .widget, + isA(), + ); + if (highlightAddHighlightContainerIsContainer) { + final highlightAddHighlightContainer = + highlightListAddHighlightContainerFinder + .evaluate() + .first + .widget as Container; + checkError( + 139, + highlightAddHighlightContainer.padding, + const EdgeInsets.all(3), + ); + checkError( + 140, + highlightAddHighlightContainer.margin, + const EdgeInsets.only(bottom: 8), + ); + checkError( + 141, + highlightAddHighlightContainer.constraints! + .widthConstraints(), + const BoxConstraints(minWidth: 68, maxWidth: 68), + ); + checkError( + 142, + highlightAddHighlightContainer.constraints! + .heightConstraints(), + const BoxConstraints(minHeight: 68, maxHeight: 68), + ); + + bool highlightAddHighlightContainerDecorationBoxDecoration = + checkError( + 143, + highlightAddHighlightContainer.decoration, + isA(), + ); + if (highlightAddHighlightContainerDecorationBoxDecoration) { + final highlightAddHighlightContainerDecoration = + highlightAddHighlightContainer.decoration + as BoxDecoration; + checkError( + 144, + highlightAddHighlightContainerDecoration.shape, + BoxShape.circle); + checkError( + 145, + highlightAddHighlightContainerDecoration.border, + Border.all(color: Colors.white, width: 1), + ); + } + } + + final highlightListAddHighlightIconContainerFinder = find.byKey( + const Key("highlight_list_add_highlight_icon_container"), + ); + + bool highlightListAddHighlightIconContainerIsAvailable = + checkError( + 146, + find.descendant( + of: highlightListAddHighlightContainerFinder, + matching: highlightListAddHighlightIconContainerFinder, + ), + findsOneWidget, + ); + if (highlightListAddHighlightIconContainerIsAvailable) { + bool highlightListAddHighlightIconContainerIsContainer = + checkError( + 147, + highlightListAddHighlightIconContainerFinder + .evaluate() + .first + .widget, + isA(), + ); + if (highlightListAddHighlightIconContainerIsContainer) { + final highlightListAddHighlightIconContainer = + highlightListAddHighlightIconContainerFinder + .evaluate() + .first + .widget as Container; + bool highlightListAddHighlightIconContainerIsBoxDecoration = + checkError( + 148, + highlightListAddHighlightIconContainer.decoration, + isA(), + ); + if (highlightListAddHighlightIconContainerIsBoxDecoration) { + final highlightListAddHighlightIconContainerDecoration = + highlightListAddHighlightIconContainer.decoration + as BoxDecoration; + checkError( + 149, + highlightListAddHighlightIconContainerDecoration.shape, + BoxShape.circle, + ); + checkError( + 150, + highlightListAddHighlightIconContainerDecoration.border, + Border.all(color: Colors.black, width: 2), + ); + } + } + + final highlightListAddHighlightIconFinder = find.byKey( + const Key("highlight_list_add_highlight_icon"), + ); + bool highlightListAddHighlightIconIsAvailable = checkError( + 151, + find.descendant( + of: highlightListAddHighlightIconContainerFinder, + matching: highlightListAddHighlightIconFinder, + ), + findsOneWidget, + ); + + if (highlightListAddHighlightIconIsAvailable) { + bool highlightListAddHighlightIconIsIcon = checkError( + 152, + highlightListAddHighlightIconFinder.evaluate().first.widget, + isA(), + ); + if (highlightListAddHighlightIconIsIcon) { + final highlightListAddHighlightIcon = + highlightListAddHighlightIconFinder + .evaluate() + .first + .widget as Icon; + checkError( + 153, + highlightListAddHighlightIcon.icon, + Icons.add, + ); + checkError( + 154, + highlightListAddHighlightIcon.color, + Colors.white, + ); + } + } + } + } + + final highlightListAddHighlightTextSizedBoxFinder = find.byKey( + const Key("highlight_list_add_highlight_text_sized_box"), + ); + bool highlightListAddHighlightTextSizedBoxIsAvailable = checkError( + 155, + find.descendant( + of: highlightListAddHighlightColumnFinder, + matching: highlightListAddHighlightTextSizedBoxFinder, + ), + findsOneWidget, + ); + + if (highlightListAddHighlightTextSizedBoxIsAvailable) { + bool highlightListAddHighlightTextSizedBoxIsSizedBox = checkError( + 156, + highlightListAddHighlightTextSizedBoxFinder + .evaluate() + .first + .widget, + isA(), + ); + if (highlightListAddHighlightTextSizedBoxIsSizedBox) { + final highlightListAddHighlightTextSizedBox = + highlightListAddHighlightTextSizedBoxFinder + .evaluate() + .first + .widget as SizedBox; + checkError( + 157, highlightListAddHighlightTextSizedBox.width, 70); + } + + final highlightListAddHighlightTextFinder = find.byKey( + const Key("highlight_list_add_highlight_text"), + ); + bool highlightListAddHighlightTextIsAvailable = checkError( + 158, + find.descendant( + of: highlightListAddHighlightTextSizedBoxFinder, + matching: highlightListAddHighlightTextFinder, + ), + findsOneWidget, + ); + + if (highlightListAddHighlightTextIsAvailable) { + bool highlightListAddHighlightTextIsText = checkError( + 159, + highlightListAddHighlightTextFinder.evaluate().first.widget, + isA(), + ); + if (highlightListAddHighlightTextIsText) { + final highlightListAddHighlightText = + highlightListAddHighlightTextFinder + .evaluate() + .first + .widget as Text; + checkError(160, highlightListAddHighlightText.data, "New"); + checkError( + 161, + highlightListAddHighlightText.overflow, + TextOverflow.ellipsis, + ); + checkError( + 162, + highlightListAddHighlightText.textAlign, + TextAlign.center, + ); + bool highlightListAddHighlightTextIsTextStyle = checkError( + 163, + highlightListAddHighlightText.style, + isA(), + ); + if (highlightListAddHighlightTextIsTextStyle) { + final highlightListAddHighlightTextStyle = + highlightListAddHighlightText.style as TextStyle; + checkError( + 164, + highlightListAddHighlightTextStyle.color, + Colors.white, + ); + } + } + } + } + } + } + } + } + }); + testWidgets("Check if Highlight Item is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + final img = stories[0]["img"]; + final name = stories[0]["name"]; + await widgetTester.pumpWidget( + MaterialApp( + home: HighlightItem( + img: img, + name: name, + ), + ), + ); + + final highlightItemPaddingFinder = find.byKey( + const Key("highlight_item_padding"), + ); + bool highlightItemPaddingIsAvailable = checkError( + 165, + find.descendant( + of: find.byType(HighlightItem), + matching: highlightItemPaddingFinder, + ), + findsOneWidget, + ); + + if (highlightItemPaddingIsAvailable) { + bool highlightItemPaddingIsPadding = checkError( + 166, + highlightItemPaddingFinder.evaluate().first.widget, + isA(), + ); + if (highlightItemPaddingIsPadding) { + final highlightItemPadding = + highlightItemPaddingFinder.evaluate().first.widget as Padding; + checkError( + 167, + highlightItemPadding.padding, + const EdgeInsets.only(right: 10, bottom: 10), + ); + } + final highlightItemColumnFinder = find.byKey( + const Key("highlight_item_column"), + ); + bool highlightItemColumnIsAvailable = checkError( + 168, + find.descendant( + of: highlightItemPaddingFinder, + matching: highlightItemColumnFinder, + ), + findsOneWidget, + ); + + if (highlightItemColumnIsAvailable) { + bool highlightItemColumnIsColumn = checkError( + 169, + highlightItemColumnFinder.evaluate().first.widget, + isA(), + ); + if (highlightItemColumnIsColumn) { + final highlightItemColumn = + highlightItemColumnFinder.evaluate().first.widget as Column; + checkError(170, highlightItemColumn.children.length, 2); + } + + final highlightItemContainerFinder = find.byKey( + const Key("highlight_item_container"), + ); + bool highlightItemContainerIsAvailable = checkError( + 171, + find.descendant( + of: highlightItemColumnFinder, + matching: highlightItemContainerFinder, + ), + findsOneWidget, + ); + if (highlightItemContainerIsAvailable) { + bool highlightItemContainerIsContainer = checkError( + 172, + highlightItemContainerFinder.evaluate().first.widget, + isA(), + ); + if (highlightItemContainerIsContainer) { + final highlightItemContainer = highlightItemContainerFinder + .evaluate() + .first + .widget as Container; + checkError( + 173, + highlightItemContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 68, maxWidth: 68), + ); + checkError( + 174, + highlightItemContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 68, maxHeight: 68), + ); + checkError( + 175, + highlightItemContainer.padding, + const EdgeInsets.all(3.0), + ); + checkError( + 176, + highlightItemContainer.margin, + const EdgeInsets.only(bottom: 8), + ); + + bool highlightItemContainerDecorationIsBoxDecoration = checkError( + 177, + highlightItemContainer.decoration, + isA(), + ); + + if (highlightItemContainerDecorationIsBoxDecoration) { + final highlightItemContainerDecoration = + highlightItemContainer.decoration as BoxDecoration; + checkError( + 178, highlightItemContainerDecoration.shape, BoxShape.circle); + checkError( + 179, + highlightItemContainerDecoration.border, + Border.all(color: Colors.grey[800]!, width: 1), + ); + } + } + } + final highlightItemImageContainerFinder = find.byKey( + const Key("highlight_item_image_container"), + ); + bool highlightItemImageContainerIsAvailable = checkError( + 180, + find.descendant( + of: highlightItemContainerFinder, + matching: highlightItemImageContainerFinder, + ), + findsOneWidget, + ); + if (highlightItemImageContainerIsAvailable) { + bool highlightItemImageContainerIsContainer = checkError( + 181, + highlightItemImageContainerFinder.evaluate().first.widget, + isA(), + ); + if (highlightItemImageContainerIsContainer) { + final highlightItemImageContainer = + highlightItemImageContainerFinder.evaluate().first.widget + as Container; + bool highlightItemImageContainerDecorationIsBoxDecoration = + checkError(182, highlightItemImageContainer.decoration, + isA()); + if (highlightItemImageContainerDecorationIsBoxDecoration) { + final highlightItemImageContainerDecoration = + highlightItemImageContainer.decoration as BoxDecoration; + checkError(183, highlightItemImageContainerDecoration.shape, + BoxShape.circle); + checkError( + 184, + highlightItemImageContainerDecoration.border, + Border.all(color: Colors.black, width: 2), + ); + bool highlightItemImageContainerDecorationImageIsDecorationImage = + checkError( + 185, + highlightItemImageContainerDecoration.image, + isA(), + ); + + if (highlightItemImageContainerDecorationImageIsDecorationImage) { + final highlightItemImageContainerDecorationImage = + highlightItemImageContainerDecoration.image + as DecorationImage; + checkError(186, highlightItemImageContainerDecorationImage.fit, + BoxFit.cover); + bool highlightItemImageContainerDecorationImageIsNetworkImage = + checkError( + 187, + highlightItemImageContainerDecorationImage.image, + isA(), + ); + + if (highlightItemImageContainerDecorationImageIsNetworkImage) { + final highlightItemImageContainerDecorationImageNetworkImage = + highlightItemImageContainerDecorationImage.image + as NetworkImage; + checkError( + 188, + highlightItemImageContainerDecorationImageNetworkImage.url, + img, + ); + } + } + } + } + } + + final highlightItemTextSizedBoxFinder = find.byKey( + const Key("highlight_item_text_sized_box"), + ); + bool highlightItemTextSizedBoxIsAvailable = checkError( + 189, + find.descendant( + of: highlightItemColumnFinder, + matching: highlightItemTextSizedBoxFinder, + ), + findsOneWidget, + ); + + if (highlightItemTextSizedBoxIsAvailable) { + bool highlightItemTextSizedBoxIsSizedBox = checkError( + 190, + highlightItemTextSizedBoxFinder.evaluate().first.widget, + isA(), + ); + if (highlightItemTextSizedBoxIsSizedBox) { + final highlightItemTextSizedBox = highlightItemTextSizedBoxFinder + .evaluate() + .first + .widget as SizedBox; + checkError(191, highlightItemTextSizedBox.width, 70); + } + final highlightItemTextFinder = find.byKey( + const Key("highlight_item_text"), + ); + bool highlightItemTextIsAvailable = checkError( + 192, + find.descendant( + of: highlightItemTextSizedBoxFinder, + matching: highlightItemTextFinder, + ), + findsOneWidget, + ); + if (highlightItemTextIsAvailable) { + bool highlightItemTextIsText = checkError( + 193, + highlightItemTextFinder.evaluate().first.widget, + isA(), + ); + if (highlightItemTextIsText) { + final highlightItemText = + highlightItemTextFinder.evaluate().first.widget as Text; + checkError( + 194, highlightItemText.overflow, TextOverflow.ellipsis); + checkError(195, highlightItemText.textAlign, TextAlign.center); + bool highlightItemTextIsTextStyle = checkError( + 196, + highlightItemText.style, + isA(), + ); + if (highlightItemTextIsTextStyle) { + final highlightItemTextStyle = + highlightItemText.style as TextStyle; + checkError(197, highlightItemTextStyle.color, Colors.white); + } + checkError(198, highlightItemText.data, name); + } + } + } + } + } + }); + testWidgets("Check if Account tab is rendered correctly", + (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + const pageIndex = 0; + + await mockNetworkImagesFor( + () => widgetTester.pumpWidget( + MaterialApp( + home: AccountTab( + pageIndex: pageIndex, + updateIndex: (updateIndex) {}, + ), + ), + ), + ); + + final accountTabRowFinder = find.byKey( + const Key("account_tab_row"), + ); + bool accountTabRowIsAvailable = checkError( + 199, + accountTabRowFinder, + findsOneWidget, + ); + if (accountTabRowIsAvailable) { + bool accountTabRowIsRow = checkError( + 200, + accountTabRowFinder.evaluate().first.widget, + isA(), + ); + if (accountTabRowIsRow) { + final accountTabRow = + accountTabRowFinder.evaluate().first.widget as Row; + checkError(201, accountTabRow.children.length, tabs.length); + } + + tabs.asMap().forEach((key, value) { + final accountTabDecoratedBoxFinder = find.byKey( + Key("account_tab_decorated_box_$key"), + ); + bool accountTabDecoratedBoxIsAvailable = checkError( + 202, + find.descendant( + of: accountTabRowFinder, + matching: accountTabDecoratedBoxFinder, + ), + findsOneWidget, + ); + + if (accountTabDecoratedBoxIsAvailable) { + bool accountTabDecoratedBoxIsDecoratedBox = checkError( + 203, + accountTabDecoratedBoxFinder.evaluate().first.widget, + isA(), + ); + if (accountTabDecoratedBoxIsDecoratedBox) { + final accountTabDecoratedBox = accountTabDecoratedBoxFinder + .evaluate() + .first + .widget as DecoratedBox; + bool accountTabDecoratedBoxDecorationIsBoxDecoration = checkError( + 204, + accountTabDecoratedBox.decoration, + isA(), + ); + if (accountTabDecoratedBoxDecorationIsBoxDecoration) { + final accountTabDecoratedBoxDecoration = + accountTabDecoratedBox.decoration as BoxDecoration; + bool accountTabDecoratedBoxDecorationBorderIsBorder = checkError( + 205, + accountTabDecoratedBoxDecoration.border, + isA(), + ); + if (accountTabDecoratedBoxDecorationBorderIsBorder) { + final accountTabDecoratedBoxDecorationBorder = + accountTabDecoratedBoxDecoration.border as Border; + bool accountTabDecoratedBoxDecorationBorderBottomIsBorderSide = + checkError( + 206, + accountTabDecoratedBoxDecorationBorder.bottom, + isA(), + ); + if (accountTabDecoratedBoxDecorationBorderBottomIsBorderSide) { + final accountTabDecoratedBoxDecorationBorderBottom = + accountTabDecoratedBoxDecorationBorder.bottom; + checkError( + 207, + accountTabDecoratedBoxDecorationBorderBottom.color, + (pageIndex == key) ? Colors.white : Colors.transparent, + ); + checkError( + 208, + accountTabDecoratedBoxDecorationBorderBottom.width, + 2, + ); + } + } + } + } + final accountTabElevatedButtonFinder = find.byKey( + Key("account_tab_elevated_button_$key"), + ); + bool accountTabElevatedButtonIsAvailable = checkError( + 209, + find.descendant( + of: accountTabDecoratedBoxFinder, + matching: accountTabElevatedButtonFinder, + ), + findsOneWidget, + ); + if (accountTabElevatedButtonIsAvailable) { + bool accountTabElevatedButtonIsElevatedButton = checkError( + 210, + accountTabElevatedButtonFinder.evaluate().first.widget, + isA(), + ); + if (accountTabElevatedButtonIsElevatedButton) { + final accountTabElevatedButton = accountTabElevatedButtonFinder + .evaluate() + .first + .widget as ElevatedButton; + bool accountTabElevatedButtonStyleIsButtonStyle = checkError( + 211, + accountTabElevatedButton.style, + isA(), + ); + if (accountTabElevatedButtonStyleIsButtonStyle) { + final accountTabElevatedButtonStyle = + accountTabElevatedButton.style as ButtonStyle; + checkError( + 212, + accountTabElevatedButtonStyle.backgroundColor! + .resolve(states), + Colors.transparent, + ); + checkError( + 213, + accountTabElevatedButtonStyle.elevation!.resolve(states), + 0, + ); + } + } + final accountTabIconFinder = find.byKey( + Key("account_tab_icon_$key"), + ); + bool accountTabIconIsAvailable = checkError( + 214, + find.descendant( + of: accountTabElevatedButtonFinder, + matching: accountTabIconFinder, + ), + findsOneWidget, + ); + if (accountTabIconIsAvailable) { + bool accountTabIconIsIcon = checkError( + 215, + accountTabIconFinder.evaluate().first.widget, + isA(), + ); + if (accountTabIconIsIcon) { + final accountTabIcon = + accountTabIconFinder.evaluate().first.widget as Icon; + checkError(216, accountTabIcon.color, Colors.white); + checkError(217, accountTabIcon.icon, tabs[key]['icon']); + } + } + } + } + }); + } + }); + testWidgets('Check if Account posts thumbnail is present', + (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + const String imageUrl = "https://picsum.photos/250?image=9"; + // mock screen size + tester.binding.window.physicalSizeTestValue = const Size(375, 812); + await mockNetworkImagesFor( + () => tester.pumpWidget( + const MaterialApp( + home: PostThumbnail(imageUrl: imageUrl), + ), + ), + ); + + final postThumbnailContainerFinder = find.byKey( + const Key(imageUrl), + ); + checkError(218, postThumbnailContainerFinder, findsOneWidget); + + final postThumbnailContainer = + postThumbnailContainerFinder.evaluate().single.widget as Container; + checkError(219, postThumbnailContainer.decoration, isA()); + + final postThumbnailContainerDecoration = + postThumbnailContainer.decoration as BoxDecoration; + checkError( + 220, + postThumbnailContainerDecoration.image, + isA(), + ); + + final postThumbnailContainerDecorationImage = + postThumbnailContainerDecoration.image as DecorationImage; + checkError( + 221, + postThumbnailContainerDecorationImage.image, + isA(), + ); + checkError( + 222, + postThumbnailContainerDecorationImage.fit, + BoxFit.cover, + ); + + final postThumbnailContainerDecorationImageNetworkImage = + postThumbnailContainerDecorationImage.image as NetworkImage; + checkError( + 223, + postThumbnailContainerDecorationImageNetworkImage.url, + imageUrl, + ); + }); + + testWidgets('Check if Bottom Navbar is present', (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: AccountPage( + posts: posts, + stories: stories, + profileData: profileJson, + ), + ), + ), + ); + + int pageIndex = 4; + + List bottomItems = [ + pageIndex == 0 + ? "assets/images/home_active_icon.svg" + : "assets/images/home_icon.svg", + pageIndex == 1 + ? "assets/images/search_active_icon.svg" + : "assets/images/search_icon.svg", + pageIndex == 2 + ? "assets/images/upload_active_icon.svg" + : "assets/images/upload_icon.svg", + pageIndex == 3 + ? "assets/images/love_active_icon.svg" + : "assets/images/love_icon.svg", + pageIndex == 4 + ? "assets/images/account_active_icon.svg" + : "assets/images/account_icon.svg", + ]; + + final bottomNavigationBarContainer = + find.byKey(const Key('bottom_navigation_bar_container')); + checkError(224, bottomNavigationBarContainer, findsOneWidget); + + final bottomNavigationBarContainerFinder = + bottomNavigationBarContainer.evaluate().first.widget as Container; + checkError( + 225, bottomNavigationBarContainerFinder.constraints!.maxHeight, 55); + checkError(226, bottomNavigationBarContainerFinder.constraints!.maxWidth, + double.infinity); + checkError(227, bottomNavigationBarContainerFinder.color, Colors.black); + checkError(228, bottomNavigationBarContainerFinder.padding, + const EdgeInsets.only(left: 20, right: 20, bottom: 20, top: 15)); + + final bottomNavigationBarRowFinder = + find.byKey(const Key('bottom_navigation_bar_row')); + checkError( + 229, + find.descendant( + of: bottomNavigationBarContainer, + matching: bottomNavigationBarRowFinder), + findsOneWidget); + + final bottomNavigationBarRow = + bottomNavigationBarRowFinder.evaluate().first.widget as Row; + checkError(230, bottomNavigationBarRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween); + checkError(231, bottomNavigationBarRow.children, hasLength(5)); + + bottomItems.asMap().forEach((index, value) { + final bottomItem = bottomNavigationBarRow.children[index] as InkWell; + checkError(232, bottomItem.onTap, isA()); + checkError(233, bottomItem.child, isA()); + + final bottomItemSvgPicture = bottomItem.child as SvgPicture; + checkError(234, bottomItemSvgPicture.pictureProvider.runtimeType, + ExactAssetPicture); + checkError(235, bottomItemSvgPicture.width, 27); + final bottomItemSvgPicturePictureProvider = + bottomItemSvgPicture.pictureProvider as ExactAssetPicture; + checkError(236, bottomItemSvgPicturePictureProvider.assetName, + bottomItems[index]); + }); + }); +} diff --git a/test/helper.dart b/test/helper.dart new file mode 100644 index 0000000..906fa9a --- /dev/null +++ b/test/helper.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +void ignoreOverflowErrors( + FlutterErrorDetails details, { + bool forceReport = false, +}) { + bool ifIsOverflowError = false; + bool isUnableToLoadAsset = false; + + // Detect overflow error. + var exception = details.exception; + if (exception is FlutterError) { + ifIsOverflowError = !exception.diagnostics.any( + (e) => e.value.toString().startsWith("A RenderFlex overflowed by"), + ); + isUnableToLoadAsset = !exception.diagnostics.any( + (e) => e.value.toString().startsWith("Unable to load asset"), + ); + } + + // Ignore if is overflow error. + if (ifIsOverflowError || isUnableToLoadAsset) { + debugPrint('Ignored Error'); + } else { + FlutterError.dumpErrorToConsole(details, forceReport: forceReport); + } +} diff --git a/test/home_page_test.dart b/test/home_page_test.dart new file mode 100644 index 0000000..5a5ab74 --- /dev/null +++ b/test/home_page_test.dart @@ -0,0 +1,1090 @@ +import 'package:example_widget_testing/app/modules/home/components/story_item.dart'; +import 'package:example_widget_testing/app/modules/home/home_page.dart'; +import 'package:example_widget_testing/app/widgets/post_item.dart'; +import 'package:example_widget_testing/core/values/constant/profile_json.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network_image_mock/network_image_mock.dart'; +// import story_json.dart' +import 'package:example_widget_testing/core/values/constant/story_json.dart'; +import 'package:example_widget_testing/core/theme/colors.dart'; +import 'package:example_widget_testing/core/values/constant/post_json.dart'; + +import 'helper.dart'; + +void checkError(int index, dynamic expected, dynamic matcher) { + try { + expect(expected, matcher); + } catch (e) { + debugPrint('Homepage Test-$index failed:'); + debugPrint(e.toString()); + } +} + +void main() { + testWidgets('Check if home page is present', (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: HomePage( + posts: posts, profileData: profileJson, stories: stories), + ), + ), + ); + final homePageFinder = find.byType(HomePage); + checkError(1, homePageFinder, findsOneWidget); + }); + + testWidgets('Check if Home page Appbar is present', + (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: HomePage( + posts: posts, profileData: profileJson, stories: stories), + ), + ), + ); + + final appBarFinder = find.byKey(const Key('app_bar_home')); + checkError(2, appBarFinder, findsOneWidget); + + final appBar = appBarFinder.evaluate().first.widget as AppBar; + checkError(3, appBar.backgroundColor, Colors.black); + checkError(4, appBar.leading, isA()); + + final appBarLeading = appBar.leading as Icon; + checkError(5, appBarLeading.icon, Icons.camera_alt); + checkError(6, appBar.title, isA
()); + + final appBarTitle = appBar.title as Center; + checkError(7, appBarTitle.child, isA()); + checkError(8, appBar.actions, isA>()); + checkError(9, appBar.actions?.length, 1); + + final appBarAction = appBar.actions?.first as Icon; + checkError(10, appBarAction.icon, Icons.send); + }); + + testWidgets('Check if Story is present', (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: HomePage( + posts: posts, profileData: profileJson, stories: stories), + ), + ), + ); + + final storyFinder = find.byKey(const Key('stories')); + checkError(11, storyFinder, findsOneWidget); + + final story = storyFinder.evaluate().first.widget as Row; + checkError(12, story.children, isA>()); + checkError(13, story.children.length, stories.length); + checkError(14, story.children[0], isA()); + + stories.asMap().forEach((index, value) { + final storyItem = story.children[index] as StoryItem; + checkError(15, storyItem.name, value['name']); + checkError(16, storyItem.img, value['img']); + }); + }); + + testWidgets('Check if StoryItem rendered correctly', + (WidgetTester tester) async { + // Define test data + const String imageUrl = 'https://example.com/image.jpg'; + const String name = 'John Doe'; + + await mockNetworkImagesFor(() => tester.pumpWidget( + const MaterialApp(home: StoryItem(img: imageUrl, name: name)))); + + checkError(17, find.byType(Container), findsNWidgets(2)); + + final storyItemPaddingFinder = find.byKey(const Key('story_item_padding')); + checkError(18, storyItemPaddingFinder, findsOneWidget); + + final storyItemPadding = + storyItemPaddingFinder.evaluate().first.widget as Padding; + checkError( + 19, + storyItemPadding.padding, + const EdgeInsets.only(right: 20, bottom: 10), + ); + + final storyItemColumnFinder = find.byKey(const Key('story_item_column')); + checkError(20, storyItemColumnFinder, findsOneWidget); + checkError( + 21, + find.descendant( + of: storyItemPaddingFinder, matching: storyItemColumnFinder), + findsOneWidget, + ); + + final storyItemColumn = + storyItemColumnFinder.evaluate().first.widget as Column; + checkError(22, storyItemColumn.children, isA>()); + checkError(23, storyItemColumn.children.length, 2); + + final storyItemContainerFinder = find.byKey( + const Key('story_item_container'), + ); + checkError( + 24, + find.descendant( + of: storyItemColumnFinder, + matching: storyItemContainerFinder, + ), + findsOneWidget, + ); + + final storyItemContainer = + storyItemContainerFinder.evaluate().first.widget as Container; + + checkError( + 25, + storyItemContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 68, maxWidth: 68), + ); + + checkError(26, storyItemContainer.margin, const EdgeInsets.only(bottom: 8)); + + checkError( + 27, + storyItemContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 68, maxHeight: 68), + ); + + checkError(29, storyItemContainer.decoration, isA()); + + final storyItemContainerDecoration = + storyItemContainer.decoration as BoxDecoration; + checkError(28, storyItemContainerDecoration.shape, BoxShape.circle); + + checkError( + 30, storyItemContainerDecoration.gradient, isA()); + final storyItemContainerGradient = + storyItemContainerDecoration.gradient as LinearGradient; + checkError(31, storyItemContainerGradient.begin, Alignment.topCenter); + checkError(32, storyItemContainerGradient.end, Alignment.bottomCenter); + checkError(33, storyItemContainerGradient.colors, + const [Color(0xFF9B2282), Color(0xFFEEA863)]); + + final storyItemImageContainerFinder = find.byKey( + const Key('story_item_image_container'), + ); + + checkError( + 34, + find.descendant( + of: storyItemContainerFinder, + matching: storyItemImageContainerFinder, + ), + findsOneWidget, + ); + + final storyItemImageContainer = + storyItemImageContainerFinder.evaluate().first.widget as Container; + + checkError( + 35, + storyItemImageContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 65, maxWidth: 65), + ); + + checkError( + 36, + storyItemImageContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 65, maxHeight: 65), + ); + + checkError(37, storyItemImageContainer.margin, const EdgeInsets.all(3)); + checkError(38, storyItemImageContainer.decoration, isA()); + + final storyItemImageContainerDecoration = + storyItemImageContainer.decoration as BoxDecoration; + checkError(39, storyItemImageContainerDecoration.shape, BoxShape.circle); + checkError( + 40, + storyItemImageContainerDecoration.border, + const Border.fromBorderSide( + BorderSide( + color: black, + width: 2, + style: BorderStyle.solid, + ), + ), + ); + + checkError( + 41, storyItemImageContainerDecoration.image, isA()); + + final storyItemImageContainerDecorationImage = + (storyItemImageContainer.decoration as BoxDecoration).image + as DecorationImage; + checkError( + 42, storyItemImageContainerDecorationImage.image, isA()); + + checkError(42, storyItemImageContainerDecorationImage.fit, BoxFit.cover); + + final storyItemUsernameSizeBoxFinder = find.byKey( + const Key('story_item_username_sizedbox'), + ); + + checkError( + 43, + find.descendant( + of: storyItemColumnFinder, matching: storyItemUsernameSizeBoxFinder), + findsOneWidget, + ); + + final storyItemUsernameSizeBox = + storyItemUsernameSizeBoxFinder.evaluate().first.widget as SizedBox; + checkError(44, storyItemUsernameSizeBox.width, 70); + + final storyItemUsernameTextFinder = find.byKey( + const Key('story_item_username_text'), + ); + + checkError( + 45, + find.descendant( + of: storyItemUsernameSizeBoxFinder, + matching: storyItemUsernameTextFinder), + findsOneWidget, + ); + + final storyItemUsernameText = + storyItemUsernameTextFinder.evaluate().first.widget as Text; + checkError(46, storyItemUsernameText.data, name); + checkError(47, storyItemUsernameText.overflow, TextOverflow.ellipsis); + checkError(48, storyItemUsernameText.style!.color, white); + }); + + testWidgets('Check if divider is present', (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + + await tester.pumpWidget( + MaterialApp( + home: + HomePage(posts: posts, profileData: profileJson, stories: stories), + ), + ); + + final dividerFinder = find.byKey(const Key('divider')); + checkError(49, dividerFinder, findsOneWidget); + + final divider = dividerFinder.evaluate().first.widget as Divider; + checkError(50, divider.color, white.withOpacity(0.3)); + }); + + testWidgets('Check if Posts Column is present', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: + HomePage(posts: posts, profileData: profileJson, stories: stories), + ), + ); + + final homePageColumnFinder = find.byKey(const Key('home_page_column')); + + final postsColumnFinder = find.byKey(const Key('posts_column')); + + checkError( + 51, + find.descendant(of: homePageColumnFinder, matching: postsColumnFinder), + findsOneWidget, + ); + checkError(52, postsColumnFinder, findsOneWidget); + + final postsColumn = postsColumnFinder.evaluate().first.widget as Column; + checkError(53, postsColumn.children.length, posts.length); + }); + + testWidgets( + 'Check if PostItem rendered correctly', + (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: PostItem( + postImg: posts[0]['postImg'], + profileImg: posts[0]['profileImg'], + name: posts[0]['name'], + caption: posts[0]['caption'], + isLoved: posts[0]['isLoved'], + viewCount: posts[0]['commentCount'], + likedBy: posts[0]['likedBy'], + dayAgo: posts[0]['timeAgo'], + userPhoto: profile, + ), + ), + ), + ); + + final postItemPaddingFinder = find.byKey(const Key('post_item_padding')); + checkError(54, postItemPaddingFinder, findsOneWidget); + + final postItemPadding = + postItemPaddingFinder.evaluate().first.widget as Padding; + checkError( + 55, postItemPadding.padding, const EdgeInsets.only(bottom: 10)); + + final postItemColumnFinder = find.byKey(const Key('post_item_column')); + checkError( + 56, + find.descendant( + of: postItemPaddingFinder, matching: postItemColumnFinder), + findsOneWidget, + ); + + final postItemColumn = + postItemColumnFinder.evaluate().first.widget as Column; + checkError( + 57, postItemColumn.crossAxisAlignment, CrossAxisAlignment.start); + checkError(58, postItemColumn.children.length, 8); + + final postItemUserInfoContainerFinder = find.byKey( + const Key('post_item_user_info_container'), + ); + + checkError( + 59, + find.descendant( + of: postItemColumnFinder, + matching: postItemUserInfoContainerFinder), + findsOneWidget, + ); + + final postItemUserInfoContainer = + postItemUserInfoContainerFinder.evaluate().first.widget as Container; + + checkError(60, postItemUserInfoContainer.padding, + const EdgeInsets.symmetric(vertical: 10, horizontal: 15)); + + checkError(61, postItemUserInfoContainer.margin, + const EdgeInsets.only(bottom: 12)); + + final postItemUserInfoRowFinder = find.byKey( + const Key('post_item_user_info_row'), + ); + checkError( + 62, + find.descendant( + of: postItemUserInfoContainerFinder, + matching: postItemUserInfoRowFinder), + findsOneWidget, + ); + + final postItemUserInfoRow = + postItemUserInfoRowFinder.evaluate().first.widget as Row; + + checkError(63, postItemUserInfoRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween); + checkError(64, postItemUserInfoRow.children.length, 3); + + final postItemUserImgContainerFinder = find.byKey( + const Key('post_item_user_profile_img_container'), + ); + + checkError( + 65, + find.descendant( + of: postItemUserInfoRowFinder, + matching: postItemUserImgContainerFinder), + findsOneWidget, + ); + + final postItemUserImgContainer = + postItemUserImgContainerFinder.evaluate().first.widget as Container; + + checkError(66, postItemUserImgContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 40, maxWidth: 40)); + checkError(67, postItemUserImgContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 40, maxHeight: 40)); + checkError(68, postItemUserImgContainer.margin, + const EdgeInsets.only(right: 15)); + checkError(69, postItemUserImgContainer.decoration, isA()); + + final postItemUserImgContainerDecoration = + postItemUserImgContainer.decoration as BoxDecoration; + checkError(70, postItemUserImgContainerDecoration.shape, BoxShape.circle); + checkError( + 71, postItemUserImgContainerDecoration.image, isA()); + + final postItemUserImgContainerDecorationImage = + postItemUserImgContainerDecoration.image as DecorationImage; + checkError(72, postItemUserImgContainerDecorationImage.image, + isA()); + checkError(73, postItemUserImgContainerDecorationImage.fit, BoxFit.cover); + + final postItemUserImgContainerDecorationImageNetworkImage = + postItemUserImgContainerDecorationImage.image as NetworkImage; + checkError(74, postItemUserImgContainerDecorationImageNetworkImage.url, + posts[0]['profileImg']); + + final postItemUserNameExpendedFinder = find.byKey( + const Key('post_item_user_name_expanded'), + ); + + checkError( + 75, + find.descendant( + of: postItemUserInfoRowFinder, + matching: postItemUserNameExpendedFinder), + findsOneWidget, + ); + + final postItemUserNameTextFinder = find.byKey( + const Key('post_item_user_name_text'), + ); + + checkError( + 76, + find.descendant( + of: postItemUserNameExpendedFinder, + matching: postItemUserNameTextFinder), + findsOneWidget, + ); + + final postItemUserNameText = + postItemUserNameTextFinder.evaluate().first.widget as Text; + checkError(77, postItemUserNameText.data, posts[0]['name']); + checkError(78, postItemUserNameText.style, isA()); + final postItemUserNameTextStyle = postItemUserNameText.style as TextStyle; + checkError(79, postItemUserNameTextStyle.color, Colors.white); + checkError(80, postItemUserNameTextStyle.fontWeight, FontWeight.w500); + checkError(81, postItemUserNameTextStyle.fontSize, 15); + + final postItemUserMoreIconFinder = find.byKey( + const Key('post_item_user_more_icon'), + ); + + checkError( + 82, + find.descendant( + of: postItemUserInfoRowFinder, + matching: postItemUserMoreIconFinder), + findsOneWidget, + ); + + final postItemUserMoreIcon = + postItemUserMoreIconFinder.evaluate().first.widget as Icon; + checkError(83, postItemUserMoreIcon.icon, Icons.more_horiz); + checkError(84, postItemUserMoreIcon.color, Colors.white); + + final postItemImageContainerFinder = find.byKey( + const Key('post_item_image_container'), + ); + checkError( + 85, + find.descendant( + of: postItemColumnFinder, matching: postItemImageContainerFinder), + findsOneWidget, + ); + + final postItemImageContainer = + postItemImageContainerFinder.evaluate().first.widget as Container; + checkError(86, postItemImageContainer.constraints!.heightConstraints(), + const BoxConstraints(maxHeight: 400, minHeight: 400)); + checkError( + 87, postItemImageContainer.margin, const EdgeInsets.only(bottom: 10)); + checkError(88, postItemImageContainer.decoration, isA()); + + final postItemImageContainerDecoration = + postItemImageContainer.decoration as BoxDecoration; + checkError( + 89, postItemImageContainerDecoration.image, isA()); + + final postItemImageContainerDecorationImage = + postItemImageContainerDecoration.image as DecorationImage; + checkError( + 90, postItemImageContainerDecorationImage.image, isA()); + checkError(91, postItemImageContainerDecorationImage.fit, BoxFit.cover); + + final postItemImageContainerDecorationImageNetworkImage = + postItemImageContainerDecorationImage.image as NetworkImage; + checkError(92, postItemImageContainerDecorationImageNetworkImage.url, + posts[0]['postImg']); + + final postItemActionContainerFinder = + find.byKey(const Key('post_item_actions_container')); + checkError( + 93, + find.descendant( + of: postItemColumnFinder, matching: postItemActionContainerFinder), + findsOneWidget, + ); + + final postItemActionContainer = + postItemActionContainerFinder.evaluate().first.widget as Container; + checkError( + 94, + postItemActionContainer.padding, + const EdgeInsets.fromLTRB(15, 3, 15, 0), + ); + checkError(95, postItemActionContainer.margin, + const EdgeInsets.only(bottom: 12)); + + final postItemActionRowFinder = find.byKey( + const Key('post_item_actions_row'), + ); + checkError( + 96, + find.descendant( + of: postItemActionContainerFinder, + matching: postItemActionRowFinder), + findsOneWidget, + ); + + final postItemActionRow = + postItemActionRowFinder.evaluate().first.widget as Row; + checkError(97, postItemActionRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween); + checkError(98, postItemActionRow.children.length, 2); + + final postItemActionsLeftRowFinder = find.byKey( + const Key('post_item_actions_left_row'), + ); + checkError( + 99, + find.descendant( + of: postItemActionRowFinder, + matching: postItemActionsLeftRowFinder), + findsOneWidget, + ); + + final postItemActionsLeftRow = + postItemActionsLeftRowFinder.evaluate().first.widget as Row; + checkError(100, postItemActionsLeftRow.children.length, 5); + + final postItemActionsLoveIconFinder = find.byKey( + const Key('post_item_actions_love_icon'), + ); + checkError( + 101, + find.descendant( + of: postItemActionsLeftRowFinder, + matching: postItemActionsLoveIconFinder), + findsOneWidget, + ); + + final postItemActionsLoveIcon = + postItemActionsLoveIconFinder.evaluate().first.widget as SvgPicture; + checkError(102, postItemActionsLoveIcon, isA()); + checkError(103, postItemActionsLoveIcon.width, 27); + checkError(104, postItemActionsLoveIcon.pictureProvider.runtimeType, + ExactAssetPicture); + + final postItemActionsLoveIconPictureProvider = + postItemActionsLoveIcon.pictureProvider as ExactAssetPicture; + checkError( + 105, + postItemActionsLoveIconPictureProvider.assetName, + posts[0]['isLoved'] + ? 'assets/images/loved_icon.svg' + : 'assets/images/love_icon.svg'); + final postItemActionsLeftRowSizeBox1Finder = find.byKey( + const Key('post_item_actions_left_row_sized_box_1'), + ); + checkError( + 106, + find.descendant( + of: postItemActionsLeftRowFinder, + matching: postItemActionsLeftRowSizeBox1Finder), + findsOneWidget, + ); + + final postItemActionsLeftRowSizeBox1 = + postItemActionsLeftRowSizeBox1Finder.evaluate().first.widget + as SizedBox; + checkError(107, postItemActionsLeftRowSizeBox1.width, 20); + + final postItemActionsCommentIconFinder = find.byKey( + const Key('post_item_actions_comment_icon'), + ); + + checkError( + 108, + find.descendant( + of: postItemActionsLeftRowFinder, + matching: postItemActionsCommentIconFinder), + findsOneWidget, + ); + + final postItemActionsCommentIcon = postItemActionsCommentIconFinder + .evaluate() + .first + .widget as SvgPicture; + checkError(109, postItemActionsCommentIcon, isA()); + + checkError(110, postItemActionsCommentIcon.width, 27); + checkError(111, postItemActionsCommentIcon.pictureProvider.runtimeType, + ExactAssetPicture); + final postItemActionsCommentIconPictureProvider = + postItemActionsCommentIcon.pictureProvider as ExactAssetPicture; + checkError(112, postItemActionsCommentIconPictureProvider.assetName, + "assets/images/comment_icon.svg"); + final postItemActionsLeftRowSizeBox2Finder = find.byKey( + const Key('post_item_actions_left_row_sized_box_2'), + ); + checkError( + 113, + find.descendant( + of: postItemActionsLeftRowFinder, + matching: postItemActionsLeftRowSizeBox2Finder), + findsOneWidget, + ); + + final postItemActionsLeftRowSizeBox2 = + postItemActionsLeftRowSizeBox2Finder.evaluate().first.widget + as SizedBox; + checkError(114, postItemActionsLeftRowSizeBox2.width, 20); + + final postItemActionsMessageIconFinder = find.byKey( + const Key('post_item_actions_message_icon'), + ); + checkError( + 115, + find.descendant( + of: postItemActionsLeftRowFinder, + matching: postItemActionsMessageIconFinder), + findsOneWidget, + ); + + final postItemActionsMessageIcon = postItemActionsMessageIconFinder + .evaluate() + .first + .widget as SvgPicture; + checkError(116, postItemActionsMessageIcon, isA()); + checkError(117, postItemActionsMessageIcon.width, 27); + checkError(118, postItemActionsMessageIcon.pictureProvider.runtimeType, + ExactAssetPicture); + + final postItemActionsMessageIconPictureProvider = + postItemActionsMessageIcon.pictureProvider as ExactAssetPicture; + checkError(119, postItemActionsMessageIconPictureProvider.assetName, + "assets/images/message_icon.svg"); + + final postItemActionsSaveIconFinder = find.byKey( + const Key('post_item_actions_save_icon'), + ); + checkError( + 120, + find.descendant( + of: postItemActionRowFinder, + matching: postItemActionsSaveIconFinder), + findsOneWidget, + ); + + final postItemActionsSaveIcon = + postItemActionsSaveIconFinder.evaluate().first.widget as SvgPicture; + checkError(121, postItemActionsSaveIcon, isA()); + checkError(122, postItemActionsSaveIcon.width, 27); + checkError(123, postItemActionsSaveIcon.pictureProvider.runtimeType, + ExactAssetPicture); + + final postItemActionsSaveIconPictureProvider = + postItemActionsSaveIcon.pictureProvider as ExactAssetPicture; + checkError(124, postItemActionsSaveIconPictureProvider.assetName, + "assets/images/save_icon.svg"); + + final postItemCaptionContainerFinder = find.byKey( + const Key('post_item_caption_container'), + ); + checkError( + 125, + find.descendant( + of: postItemColumnFinder, matching: postItemCaptionContainerFinder), + findsOneWidget, + ); + + final postItemCaptionContainer = + postItemCaptionContainerFinder.evaluate().first.widget as Container; + checkError(126, postItemCaptionContainer, isA()); + checkError(127, postItemCaptionContainer.padding, + const EdgeInsets.symmetric(horizontal: 15)); + checkError(128, postItemCaptionContainer.margin, + const EdgeInsets.only(bottom: 12)); + + final postItemCaptionRichTextFinder = find.byKey( + const Key('post_item_caption_rich_text'), + ); + checkError( + 129, + find.descendant( + of: postItemCaptionContainerFinder, + matching: postItemCaptionRichTextFinder), + findsOneWidget, + ); + final postItemCaptionRichText = + postItemCaptionRichTextFinder.evaluate().first.widget as RichText; + checkError(130, postItemCaptionRichText.text, isA()); + + final postItemCaptionRichTextTextSpan = + postItemCaptionRichText.text as TextSpan; + checkError(131, postItemCaptionRichTextTextSpan.children, hasLength(2)); + + final postItemCaptionRichTextTextSpanTextSpan1 = + postItemCaptionRichTextTextSpan.children![0] as TextSpan; + checkError(132, postItemCaptionRichTextTextSpanTextSpan1.text, + posts[0]['name'] + ' '); + checkError(133, postItemCaptionRichTextTextSpanTextSpan1.style, + const TextStyle(fontSize: 15, fontWeight: FontWeight.w700)); + + final postItemCaptionRichTextTextSpanTextSpan2 = + postItemCaptionRichTextTextSpan.children![1] as TextSpan; + checkError(134, postItemCaptionRichTextTextSpanTextSpan2.text, + posts[0]['caption']); + checkError(135, postItemCaptionRichTextTextSpanTextSpan2.style, + const TextStyle(fontSize: 15, fontWeight: FontWeight.w500)); + + final postItemViewCommentsContainerFinder = find.byKey( + const Key('post_item_view_comments_container'), + ); + checkError( + 136, + find.descendant( + of: postItemColumnFinder, + matching: postItemViewCommentsContainerFinder), + findsOneWidget, + ); + final postItemViewCommentsContainer = postItemViewCommentsContainerFinder + .evaluate() + .first + .widget as Container; + checkError(137, postItemViewCommentsContainer.padding, + const EdgeInsets.symmetric(horizontal: 15)); + checkError(138, postItemViewCommentsContainer.margin, + const EdgeInsets.only(bottom: 12)); + + final postItemViewCommentsTextFinder = find.byKey( + const Key('post_item_view_comments_text'), + ); + checkError( + 139, + find.descendant( + of: postItemViewCommentsContainerFinder, + matching: postItemViewCommentsTextFinder), + findsOneWidget, + ); + final postItemViewCommentsText = + postItemViewCommentsTextFinder.evaluate().first.widget as Text; + checkError(140, postItemViewCommentsText.data, + "View ${posts[0]['commentCount']} comments"); + checkError(141, postItemViewCommentsText.style, isA()); + checkError( + 142, postItemViewCommentsText.style!.color, white.withOpacity(0.5)); + checkError(143, postItemViewCommentsText.style!.fontSize, 15); + checkError( + 144, postItemViewCommentsText.style!.fontWeight, FontWeight.w500); + + final postItemAddCommentContainerFinder = find.byKey( + const Key('post_item_add_comment_container'), + ); + checkError( + 145, + find.descendant( + of: postItemColumnFinder, + matching: postItemAddCommentContainerFinder), + findsOneWidget, + ); + + final postItemAddCommentContainer = postItemAddCommentContainerFinder + .evaluate() + .first + .widget as Container; + checkError(146, postItemAddCommentContainer.padding, + const EdgeInsets.symmetric(horizontal: 15)); + checkError(147, postItemAddCommentContainer.margin, + const EdgeInsets.only(bottom: 12)); + + final postItemAddCommentRowFinder = find.byKey( + const Key('post_item_add_comment_row'), + ); + checkError( + 148, + find.descendant( + of: postItemAddCommentContainerFinder, + matching: postItemAddCommentRowFinder), + findsOneWidget, + ); + + final postItemAddCommentRow = + postItemAddCommentRowFinder.evaluate().first.widget as Row; + checkError(149, postItemAddCommentRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween); + checkError(150, postItemAddCommentRow.children, hasLength(2)); + + final postItemAddCommentLeftRowFinder = find.byKey( + const Key('post_item_add_comment_left_row'), + ); + checkError( + 151, + find.descendant( + of: postItemAddCommentRowFinder, + matching: postItemAddCommentLeftRowFinder), + findsOneWidget, + ); + + final postItemAddCommentLeftRow = + postItemAddCommentLeftRowFinder.evaluate().first.widget as Row; + checkError(152, postItemAddCommentLeftRow.children, hasLength(2)); + + final postItemAddCommentAvatarContainerFinder = find.byKey( + const Key('post_item_add_comment_avatar_container'), + ); + checkError( + 153, + find.descendant( + of: postItemAddCommentLeftRowFinder, + matching: postItemAddCommentAvatarContainerFinder), + findsOneWidget, + ); + + final postItemAddCommentAvatarContainer = + postItemAddCommentAvatarContainerFinder.evaluate().first.widget + as Container; + checkError( + 154, + postItemAddCommentAvatarContainer.constraints!.widthConstraints(), + const BoxConstraints(minWidth: 30, maxWidth: 30)); + checkError( + 155, + postItemAddCommentAvatarContainer.constraints!.heightConstraints(), + const BoxConstraints(minHeight: 30, maxHeight: 30)); + checkError(156, postItemAddCommentAvatarContainer.margin, + const EdgeInsets.only(right: 15)); + checkError(157, postItemAddCommentAvatarContainer.decoration, + isA()); + + final postItemAddCommentAvatarContainerDecoration = + postItemAddCommentAvatarContainer.decoration as BoxDecoration; + checkError(158, postItemAddCommentAvatarContainerDecoration.shape, + BoxShape.circle); + checkError(159, postItemAddCommentAvatarContainerDecoration.image, + isA()); + + final postItemAddCommentAvatarContainerDecorationImage = + postItemAddCommentAvatarContainerDecoration.image as DecorationImage; + checkError(160, postItemAddCommentAvatarContainerDecorationImage.image, + isA()); + checkError(161, postItemAddCommentAvatarContainerDecorationImage.fit, + BoxFit.cover); + + final postItemAddCommentAvatarContainerDecorationImageNetworkImage = + postItemAddCommentAvatarContainerDecorationImage.image + as NetworkImage; + checkError( + 162, + postItemAddCommentAvatarContainerDecorationImageNetworkImage.url, + profile); + + final postItemAddCommentTextFinder = find.byKey( + const Key('post_item_add_comment_text'), + ); + checkError( + 163, + find.descendant( + of: postItemAddCommentLeftRowFinder, + matching: postItemAddCommentTextFinder), + findsOneWidget, + ); + + final postItemAddCommentText = + postItemAddCommentTextFinder.evaluate().first.widget as Text; + checkError(164, postItemAddCommentText.data, 'Add a comment...'); + checkError(165, postItemAddCommentText.style, isA()); + checkError( + 166, postItemAddCommentText.style!.color, white.withOpacity(0.5)); + checkError(167, postItemAddCommentText.style!.fontSize, 15); + checkError( + 168, postItemAddCommentText.style!.fontWeight, FontWeight.w500); + + final postItemAddCommentRightRowFinder = + find.byKey(const Key('post_item_add_comment_right_row')); + checkError( + 169, + find.descendant( + of: postItemAddCommentRowFinder, + matching: postItemAddCommentRightRowFinder), + findsOneWidget); + + final postItemAddCommentRightRow = + postItemAddCommentRightRowFinder.evaluate().first.widget as Row; + checkError(170, postItemAddCommentRightRow.children, hasLength(5)); + + final postItemAddLaughEmojiTextFinder = find.byKey( + const Key('post_item_add_laugh_emoji_text'), + ); + checkError( + 171, + find.descendant( + of: postItemAddCommentRightRowFinder, + matching: postItemAddLaughEmojiTextFinder), + findsOneWidget, + ); + + final postItemAddLaughEmojiText = + postItemAddLaughEmojiTextFinder.evaluate().first.widget as Text; + checkError(172, postItemAddLaughEmojiText.data, '😂'); + checkError( + 173, postItemAddLaughEmojiText.style, const TextStyle(fontSize: 20)); + + final postItemAddLoveEmojiTextFinder = find.byKey( + const Key('post_item_add_love_emoji_text'), + ); + checkError( + 174, + find.descendant( + of: postItemAddCommentRightRowFinder, + matching: postItemAddLoveEmojiTextFinder), + findsOneWidget, + ); + + final postItemAddLoveEmojiText = + postItemAddLoveEmojiTextFinder.evaluate().first.widget as Text; + checkError(175, postItemAddLoveEmojiText.data, '😍'); + checkError( + 176, postItemAddLoveEmojiText.style, const TextStyle(fontSize: 20)); + + final postItemAddCircleIconFinder = find.byKey( + const Key('post_item_add_circle_icon'), + ); + checkError( + 177, + find.descendant( + of: postItemAddCommentRightRowFinder, + matching: postItemAddCircleIconFinder), + findsOneWidget, + ); + + final postItemAddCircleIcon = + postItemAddCircleIconFinder.evaluate().first.widget as Icon; + checkError(178, postItemAddCircleIcon.icon, Icons.add_circle); + checkError(179, postItemAddCircleIcon.size, 18); + checkError(180, postItemAddCircleIcon.color, white.withOpacity(0.5)); + + final postItemDayAgoPaddingFinder = find.byKey( + const Key('post_item_day_ago_padding'), + ); + checkError( + 181, + find.descendant( + of: postItemColumnFinder, matching: postItemDayAgoPaddingFinder), + findsOneWidget, + ); + + final postItemDayAgoPadding = + postItemDayAgoPaddingFinder.evaluate().first.widget as Padding; + checkError(182, postItemDayAgoPadding.padding, + const EdgeInsets.symmetric(horizontal: 15)); + + final postItemDayAgoTextFinder = find.byKey( + const Key('post_item_day_ago_text'), + ); + checkError( + 183, + find.descendant( + of: postItemDayAgoPaddingFinder, + matching: postItemDayAgoTextFinder), + findsOneWidget, + ); + + final postItemDayAgoText = + postItemDayAgoTextFinder.evaluate().first.widget as Text; + checkError(184, postItemDayAgoText.data, posts[0]['timeAgo']); + checkError(185, postItemDayAgoText.style!.color, white.withOpacity(0.5)); + checkError(186, postItemDayAgoText.style!.fontSize, 15); + checkError(187, postItemDayAgoText.style!.fontWeight, FontWeight.w500); + }, + ); + + testWidgets('Check if Bottom Navbar is present', (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: HomePage( + posts: posts, profileData: profileJson, stories: stories), + ), + ), + ); + + int pageIndex = 0; + + List bottomItems = [ + pageIndex == 0 + ? "assets/images/home_active_icon.svg" + : "assets/images/home_icon.svg", + pageIndex == 1 + ? "assets/images/search_active_icon.svg" + : "assets/images/search_icon.svg", + pageIndex == 2 + ? "assets/images/upload_active_icon.svg" + : "assets/images/upload_icon.svg", + pageIndex == 3 + ? "assets/images/love_active_icon.svg" + : "assets/images/love_icon.svg", + pageIndex == 4 + ? "assets/images/account_active_icon.svg" + : "assets/images/account_icon.svg", + ]; + + final bottomNavigationBarContainer = + find.byKey(const Key('bottom_navigation_bar_container')); + checkError(188, bottomNavigationBarContainer, findsOneWidget); + + final bottomNavigationBarContainerFinder = + bottomNavigationBarContainer.evaluate().first.widget as Container; + checkError( + 189, bottomNavigationBarContainerFinder.constraints!.maxHeight, 55); + checkError(190, bottomNavigationBarContainerFinder.constraints!.maxWidth, + double.infinity); + checkError(191, bottomNavigationBarContainerFinder.color, black); + checkError(192, bottomNavigationBarContainerFinder.padding, + const EdgeInsets.only(left: 20, right: 20, bottom: 20, top: 15)); + + final bottomNavigationBarRowFinder = + find.byKey(const Key('bottom_navigation_bar_row')); + checkError( + 193, + find.descendant( + of: bottomNavigationBarContainer, + matching: bottomNavigationBarRowFinder), + findsOneWidget); + + final bottomNavigationBarRow = + bottomNavigationBarRowFinder.evaluate().first.widget as Row; + checkError(194, bottomNavigationBarRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween); + checkError(195, bottomNavigationBarRow.children, hasLength(5)); + + bottomItems.asMap().forEach((index, value) { + final bottomItem = bottomNavigationBarRow.children[index] as InkWell; + checkError(196, bottomItem.onTap, isA()); + checkError(197, bottomItem.child, isA()); + + final bottomItemSvgPicture = bottomItem.child as SvgPicture; + checkError(198, bottomItemSvgPicture.pictureProvider.runtimeType, + ExactAssetPicture); + checkError(199, bottomItemSvgPicture.width, 27); + + final bottomItemSvgPicturePictureProvider = + bottomItemSvgPicture.pictureProvider as ExactAssetPicture; + checkError(200, bottomItemSvgPicturePictureProvider.assetName, + bottomItems[index]); + }); + }); +} diff --git a/test/login_page_test.dart b/test/login_page_test.dart new file mode 100644 index 0000000..ef82eb8 --- /dev/null +++ b/test/login_page_test.dart @@ -0,0 +1,434 @@ +import 'package:example_widget_testing/app/modules/login/login_page.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'helper.dart'; + +void main() { + final states = {}; + + testWidgets('Check if language dropdown is present', (tester) async { + FlutterError.onError = ignoreOverflowErrors; + // choose the widget to be tested + await tester.pumpWidget( + const MaterialApp(home: LoginPage()), + ); + + // execute the test + final dropdownButtonFinder = find.byType(DropdownButton); + final dropdownButton = + dropdownButtonFinder.evaluate().first.widget as DropdownButton; + // check if dropdownButtonFinder has icon + + // check the widget + expect(dropdownButtonFinder, findsOneWidget); + try { + expect(dropdownButton.dropdownColor, Colors.white); + } catch (exception) { + debugPrint('Test-1.1 failed: $exception'); + } + + expect(dropdownButton.style!.color, Colors.black54); + expect(dropdownButton.elevation, 10); + expect(dropdownButton.items!.length, 4); + expect(dropdownButton.items![0].value, 'English'); + expect(dropdownButton.items![1].value, 'Arabic'); + expect(dropdownButton.items![2].value, 'Italian'); + expect(dropdownButton.items![3].value, 'French'); + // check if DropdownMenuItem has Text widget + expect(dropdownButton.items![0].child, isA()); + expect(dropdownButton.items![1].child, isA()); + expect(dropdownButton.items![2].child, isA()); + expect(dropdownButton.items![3].child, isA()); + // check if Text widget has correct text + expect((dropdownButton.items![0].child as Text).data, 'English'); + expect((dropdownButton.items![1].child as Text).data, 'Arabic'); + expect((dropdownButton.items![2].child as Text).data, 'Italian'); + expect((dropdownButton.items![3].child as Text).data, 'French'); + // check if Text widget has correct style + expect((dropdownButton.items![0].child as Text).style!.fontSize, 16); + expect((dropdownButton.items![1].child as Text).style!.fontSize, 16); + expect((dropdownButton.items![2].child as Text).style!.fontSize, 16); + expect((dropdownButton.items![3].child as Text).style!.fontSize, 16); + }); + + testWidgets('Check if username textbox is present', (tester) async { + FlutterError.onError = ignoreOverflowErrors; + debugPrint('test 2'); + + tester.binding.window.physicalSizeTestValue = const Size(360, 640); + + addTearDown(tester.binding.window.clearPhysicalSizeTestValue); + + await tester.pumpWidget( + const MaterialApp( + home: LoginPage(), + ), + ); + + final usernameTextboxFinder = find.byKey( + const Key('username_textfield'), + ); + // expect if username textbox has correct style + final usernameTextbox = + usernameTextboxFinder.evaluate().first.widget as TextField; + try { + expect(usernameTextboxFinder, findsOneWidget); + } catch (e) { + debugPrint('Test-1.8 failed: $e'); + } + + try { + expect(usernameTextbox.decoration!.hintText, + 'Phone number , email or username'); + } catch (e) { + debugPrint('Test-1.9 failed: $e'); + } + try { + // check if username font size is correct for different screen size + expect(usernameTextbox.style!.fontSize, 15); + // console log screen size + } catch (e) { + debugPrint('Test-60 failed:'); + debugPrint(e.toString()); + } + }); + + // check if password textbox is present + testWidgets('Check if password textbox is present', (tester) async { + FlutterError.onError = ignoreOverflowErrors; + debugPrint('test 3'); + + tester.binding.window.physicalSizeTestValue = const Size(360, 640); + + addTearDown(tester.binding.window.clearPhysicalSizeTestValue); + + await tester.pumpWidget( + const MaterialApp( + home: LoginPage(), + ), + ); + + final passwordTextboxFinder = find.byKey( + const Key('password_textfield'), + ); + // expect if password textbox has correct style + final passwordTextbox = + passwordTextboxFinder.evaluate().first.widget as TextField; + try { + expect(passwordTextboxFinder, findsOneWidget); + } catch (e) { + debugPrint('Test-61 failed: $e'); + } + + try { + expect(passwordTextbox.decoration!.hintText, 'Password'); + } catch (e) { + debugPrint('Test-62 failed: $e'); + } + // try to input password and check if it is obscured + try { + await tester.enterText(passwordTextboxFinder, 'password'); + expect(passwordTextbox.obscureText, true); + } catch (e) { + debugPrint('Test-63 failed: $e'); + } + }); + + testWidgets('Check if login button is present', (tester) async { + FlutterError.onError = ignoreOverflowErrors; + debugPrint('test 4'); + + await tester.pumpWidget( + const MaterialApp( + home: LoginPage(), + ), + ); + + final loginButtonFinder = find.byKey( + const Key('login_button'), + ); + // expect if login button has correct style + final loginButton = + loginButtonFinder.evaluate().first.widget as ElevatedButton; + try { + expect(loginButtonFinder, findsOneWidget); + } catch (e) { + debugPrint('Test-64 failed: $e'); + } + try { + expect( + loginButton.style!.backgroundColor!.resolve(states), + const Color(0xff78c9ff), + ); + } catch (e) { + debugPrint('Test-65 failed:'); + debugPrint(e.toString()); + } + }); + + testWidgets('Check Forgot Login Text', (tester) async { + FlutterError.onError = ignoreOverflowErrors; + debugPrint('test 5'); + + await tester.pumpWidget( + const MaterialApp( + home: LoginPage(), + ), + ); + + final forgotAccessFinder = find.byKey( + const Key('forgot_access_text'), + ); + + final forgotAccessText = forgotAccessFinder.evaluate().first.widget as Text; + + try { + expect(forgotAccessFinder, findsOneWidget); + } catch (e) { + debugPrint('Test-66 failed: $e'); + } + + try { + expect(forgotAccessText.data, 'Forgot your login details? '); + } catch (e) { + debugPrint('Test-67 failed: $e'); + } + + try { + expect(forgotAccessText.style!.fontSize, 13); + } catch (e) { + debugPrint('Test-68 failed: $e'); + } + + try { + expect(forgotAccessText.style!.color, Colors.black); + } catch (e) { + debugPrint('Test-69 failed: $e'); + } + + try { + expect(forgotAccessText.style!.fontWeight, FontWeight.normal); + } catch (e) { + debugPrint('Test-70 failed: $e'); + } + }); + + testWidgets('Check if Get Help text is present', (tester) async { + FlutterError.onError = ignoreOverflowErrors; + debugPrint('test 6'); + + await tester.pumpWidget( + const MaterialApp( + home: LoginPage(), + ), + ); + + final getHelpFinder = find.byKey( + const Key('get_help_text'), + ); + + final getHelpText = getHelpFinder.evaluate().first.widget as Text; + + try { + expect(getHelpFinder, findsOneWidget); + } catch (e) { + debugPrint('Test-71 failed: $e'); + } + + try { + expect(getHelpText.data, 'Get help'); + } catch (e) { + debugPrint('Test-72 failed: $e'); + } + + try { + expect(getHelpText.style!.fontSize, 13); + } catch (e) { + debugPrint('Test-73 failed: $e'); + } + + try { + expect( + getHelpText.style!.color, + const Color(0xff002588), + ); + } catch (e) { + debugPrint('Test-74 failed: $e'); + } + + try { + expect(getHelpText.style!.fontWeight, FontWeight.bold); + } catch (e) { + debugPrint('Test-75 failed: $e'); + } + }); + + testWidgets('Check if Facebook login is present', (tester) async { + FlutterError.onError = ignoreOverflowErrors; + debugPrint('test 7'); + + await tester.pumpWidget( + const MaterialApp( + home: LoginPage(), + ), + ); + + final facebookLoginFinder = find.byKey( + const Key('facebook_login'), + ); + + try { + expect(facebookLoginFinder, findsOneWidget); + } catch (e) { + debugPrint('Test-76 failed: $e'); + } + + final facebookLogo = find.byKey(const Key('facebook_logo')); + + try { + expect(facebookLogo, findsOneWidget); + } catch (e) { + debugPrint('Test-77 failed: $e'); + } + + final facebookTextFinder = find.byKey( + const Key('facebook_login_text'), + ); + + final facebookText = facebookTextFinder.evaluate().first.widget as Text; + + try { + expect(facebookTextFinder, findsOneWidget); + } catch (e) { + debugPrint('Test-78 failed: $e'); + } + + try { + expect(facebookText.data, 'Login with facebook'); + } catch (e) { + debugPrint('Test-79 failed: $e'); + } + + try { + expect( + facebookText.style!.color, + const Color(0xff1877f2), + ); + } catch (e) { + debugPrint('Test-81 failed: $e'); + } + + try { + expect(facebookText.style!.fontWeight, FontWeight.w800); + } catch (e) { + debugPrint('Test-82 failed: $e'); + } + }); + + testWidgets('Check if signup text is present', (tester) async { + FlutterError.onError = ignoreOverflowErrors; + debugPrint('test 8'); + + await tester.pumpWidget( + const MaterialApp( + home: LoginPage(), + ), + ); + + final signupSectionFinder = find.byKey(const Key('signup_section')); + final signupSection = signupSectionFinder.evaluate().first.widget as Row; + + try { + expect(signupSectionFinder, findsOneWidget); + } catch (e) { + debugPrint('Test-82 failed:'); + debugPrint(e.toString()); + } + + try { + expect(signupSection.children.length, 2); + } catch (e) { + debugPrint('Test-83 failed:'); + debugPrint(e.toString()); + } + + try { + expect(signupSection.mainAxisAlignment, MainAxisAlignment.center); + } catch (e) { + debugPrint('Test-84 failed:'); + debugPrint(e.toString()); + } + + final signupText = signupSection.children[0] as Text; + + try { + expect(signupText.runtimeType, Text); + } catch (e) { + debugPrint('Test-85 failed:'); + debugPrint(e.toString()); + } + + try { + expect(signupText.data, "Don't have an account? "); + } catch (e) { + debugPrint('Test-86 failed:'); + debugPrint(e.toString()); + } + + try { + expect(signupText.style!.fontSize, + tester.binding.window.physicalSize.width * .040 / 3); + } catch (e) { + debugPrint('Test-87 failed:'); + debugPrint(e.toString()); + } + + final signupButton = signupSection.children[1] as TextButton; + + try { + expect(signupButton.runtimeType, TextButton); + } catch (e) { + debugPrint('Test-88 failed:'); + debugPrint(e.toString()); + } + + final signupButtonText = signupButton.child as Text; + + try { + expect(signupButtonText.runtimeType, Text); + } catch (e) { + debugPrint('Test-89 failed:'); + debugPrint(e.toString()); + } + + try { + expect(signupButtonText.data, 'Sign up'); + } catch (e) { + debugPrint('Test-90 failed:'); + debugPrint(e.toString()); + } + + try { + expect(signupButtonText.style!.color, const Color(0xff00258B)); + } catch (e) { + debugPrint('Test-91 failed:'); + debugPrint(e.toString()); + } + + try { + expect(signupButtonText.style!.fontWeight, FontWeight.bold); + } catch (e) { + debugPrint('Test-92 failed:'); + debugPrint(e.toString()); + } + + try { + expect(signupButtonText.style!.fontSize, + tester.binding.window.physicalSize.width * .040 / 3); + } catch (e) { + debugPrint('Test-93 failed:'); + debugPrint(e.toString()); + } + }); +} diff --git a/test/post_page_test.dart b/test/post_page_test.dart new file mode 100644 index 0000000..e69de29 diff --git a/test/search_page_test.dart b/test/search_page_test.dart new file mode 100644 index 0000000..7be9110 --- /dev/null +++ b/test/search_page_test.dart @@ -0,0 +1,326 @@ +import 'package:example_widget_testing/app/modules/search/search_page.dart'; +import 'package:example_widget_testing/app/widgets/post_thumbnail.dart'; +import 'package:example_widget_testing/core/theme/colors.dart'; +import 'package:example_widget_testing/core/values/constant/search_json.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network_image_mock/network_image_mock.dart'; + +import 'helper.dart'; + +void checkError(int index, dynamic expected, dynamic matcher) { + try { + expect(expected, matcher); + } catch (e) { + debugPrint('Searchpage Test-$index failed:'); + debugPrint(e.toString()); + } +} + +void main() { + testWidgets('Check if Search page is present', (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: SearchPage(searchPosts: searchImages), + ), + ), + ); + + final searchPageListviewFinder = find.byKey( + const Key('search_page_listview'), + ); + checkError( + 1, + searchPageListviewFinder, + findsOneWidget, + ); + }); + + testWidgets('Check if search textfield is present', + (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: SearchPage(searchPosts: searchImages), + ), + ), + ); + + final searchPageListviewFinder = find.byKey( + const Key('search_page_listview'), + ); + + final searchPageTextfieldContainerFinder = find.byKey( + const Key('search_page_textfield_container'), + ); + // mock screen size + tester.binding.window.physicalSizeTestValue = const Size(375, 812); + checkError( + 2, + find.descendant( + of: searchPageListviewFinder, + matching: searchPageTextfieldContainerFinder, + ), + findsOneWidget); + final searchPageTextfieldContainer = searchPageTextfieldContainerFinder + .evaluate() + .single + .widget as Container; + + checkError( + 3, + searchPageTextfieldContainer.margin, + const EdgeInsets.only( + bottom: 15, + left: 15, + right: 15, + ), + ); + + checkError(4, searchPageTextfieldContainer.constraints!.maxHeight, 45.0); + checkError( + 5, + searchPageTextfieldContainer.decoration, + isA(), + ); + + final searchPageTextfieldContainerDecoration = + searchPageTextfieldContainer.decoration as BoxDecoration; + checkError( + 6, + searchPageTextfieldContainerDecoration.borderRadius, + const BorderRadius.all(Radius.circular(10)), + ); + checkError( + 7, + searchPageTextfieldContainerDecoration.color, + const Color(0xff262626), + ); + + final searchPageTextfieldFinder = find.byKey( + const Key('search_page_textfield'), + ); + checkError( + 8, + find.descendant( + of: searchPageListviewFinder, + matching: searchPageTextfieldFinder, + ), + findsOneWidget, + ); + + final searchPageTextfield = + searchPageTextfieldFinder.evaluate().single.widget as TextField; + checkError(9, searchPageTextfield.cursorColor, white.withOpacity(0.3)); + checkError(10, searchPageTextfield.style, isA()); + + final searchPageTextfieldStyle = searchPageTextfield.style as TextStyle; + checkError(11, searchPageTextfieldStyle.color, white.withOpacity(0.3)); + + checkError(12, searchPageTextfield.decoration, isA()); + + final searchPageTextfieldDecoration = + searchPageTextfield.decoration as InputDecoration; + checkError(13, searchPageTextfieldDecoration.border, InputBorder.none); + checkError(14, searchPageTextfieldDecoration.prefixIcon, isA()); + + final searchPageTextfieldPrefixIcon = + searchPageTextfieldDecoration.prefixIcon as Icon; + checkError(15, searchPageTextfieldPrefixIcon.icon, Icons.search); + checkError(16, searchPageTextfieldPrefixIcon.color, white.withOpacity(0.3)); + + final searchPageWrapFinder = find.byKey( + const Key('search_page_wrap'), + ); + checkError( + 17, + find.descendant( + of: searchPageListviewFinder, + matching: searchPageWrapFinder, + ), + findsOneWidget, + ); + + final searchPageWrap = + searchPageWrapFinder.evaluate().single.widget as Wrap; + checkError(18, searchPageWrap.spacing, 1); + checkError(19, searchPageWrap.runSpacing, 1); + checkError(20, searchPageWrap.children.length, searchImages.length); + }); + + testWidgets('Check if search posts is present', (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: SearchPage(searchPosts: searchImages), + ), + ), + ); + + final searchPageListviewFinder = find.byKey( + const Key('search_page_listview'), + ); + final searchPageWrapFinder = find.byKey( + const Key('search_page_wrap'), + ); + checkError( + 21, + find.descendant( + of: searchPageListviewFinder, + matching: searchPageWrapFinder, + ), + findsOneWidget, + ); + checkError( + 22, + find.descendant( + of: searchPageWrapFinder, + matching: find.byType(Container), + ), + findsNWidgets(searchImages.length), + ); + }); + + testWidgets('Check if search posts thumbnail is present', + (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + const String imageUrl = "https://picsum.photos/250?image=9"; + // mock screen size + tester.binding.window.physicalSizeTestValue = const Size(375, 812); + await mockNetworkImagesFor( + () => tester.pumpWidget( + const MaterialApp( + home: PostThumbnail(imageUrl: imageUrl), + ), + ), + ); + + final postThumbnailContainerFinder = find.byKey( + const Key(imageUrl), + ); + checkError(23, postThumbnailContainerFinder, findsOneWidget); + + final postThumbnailContainer = + postThumbnailContainerFinder.evaluate().single.widget as Container; + checkError(24, postThumbnailContainer.decoration, isA()); + + final postThumbnailContainerDecoration = + postThumbnailContainer.decoration as BoxDecoration; + checkError( + 25, + postThumbnailContainerDecoration.image, + isA(), + ); + + final postThumbnailContainerDecorationImage = + postThumbnailContainerDecoration.image as DecorationImage; + checkError( + 26, + postThumbnailContainerDecorationImage.image, + isA(), + ); + checkError( + 27, + postThumbnailContainerDecorationImage.fit, + BoxFit.cover, + ); + + final postThumbnailContainerDecorationImageNetworkImage = + postThumbnailContainerDecorationImage.image as NetworkImage; + checkError( + 28, + postThumbnailContainerDecorationImageNetworkImage.url, + imageUrl, + ); + }); + + testWidgets('Check if Bottom Navbar is present', (WidgetTester tester) async { + FlutterError.onError = ignoreOverflowErrors; + + await mockNetworkImagesFor( + () => tester.pumpWidget( + MaterialApp( + home: SearchPage(searchPosts: searchImages), + ), + ), + ); + + int pageIndex = 1; + + final bottomItem2Finder = find.byKey( + const Key('bottom_item_1'), + ); + checkError(29, bottomItem2Finder, findsOneWidget); + + await tester.ensureVisible(bottomItem2Finder); + await tester.pumpAndSettle(); + await tester.tap(bottomItem2Finder); + + List bottomItems = [ + pageIndex == 0 + ? "assets/images/home_active_icon.svg" + : "assets/images/home_icon.svg", + pageIndex == 1 + ? "assets/images/search_active_icon.svg" + : "assets/images/search_icon.svg", + pageIndex == 2 + ? "assets/images/upload_active_icon.svg" + : "assets/images/upload_icon.svg", + pageIndex == 3 + ? "assets/images/love_active_icon.svg" + : "assets/images/love_icon.svg", + pageIndex == 4 + ? "assets/images/account_active_icon.svg" + : "assets/images/account_icon.svg", + ]; + + final bottomNavigationBarContainer = + find.byKey(const Key('bottom_navigation_bar_container')); + checkError(188, bottomNavigationBarContainer, findsOneWidget); + + final bottomNavigationBarContainerFinder = + bottomNavigationBarContainer.evaluate().first.widget as Container; + checkError( + 189, bottomNavigationBarContainerFinder.constraints!.maxHeight, 55); + checkError(190, bottomNavigationBarContainerFinder.constraints!.maxWidth, + double.infinity); + checkError(191, bottomNavigationBarContainerFinder.color, black); + checkError(192, bottomNavigationBarContainerFinder.padding, + const EdgeInsets.only(left: 20, right: 20, bottom: 20, top: 15)); + + final bottomNavigationBarRowFinder = + find.byKey(const Key('bottom_navigation_bar_row')); + checkError( + 193, + find.descendant( + of: bottomNavigationBarContainer, + matching: bottomNavigationBarRowFinder), + findsOneWidget); + + final bottomNavigationBarRow = + bottomNavigationBarRowFinder.evaluate().first.widget as Row; + checkError(194, bottomNavigationBarRow.mainAxisAlignment, + MainAxisAlignment.spaceBetween); + checkError(195, bottomNavigationBarRow.children, hasLength(5)); + + bottomItems.asMap().forEach((index, value) { + final bottomItem = bottomNavigationBarRow.children[index] as InkWell; + checkError(196, bottomItem.onTap, isA()); + checkError(197, bottomItem.child, isA()); + + final bottomItemSvgPicture = bottomItem.child as SvgPicture; + checkError(198, bottomItemSvgPicture.pictureProvider.runtimeType, + ExactAssetPicture); + checkError(199, bottomItemSvgPicture.width, 27); + final bottomItemSvgPicturePictureProvider = + bottomItemSvgPicture.pictureProvider as ExactAssetPicture; + checkError(200, bottomItemSvgPicturePictureProvider.assetName, + bottomItems[index]); + }); + }); +}