├── android
├── settings_aar.gradle
├── gradle.properties
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── drawable
│ │ │ │ │ └── launch_background.xml
│ │ │ │ └── values
│ │ │ │ │ └── styles.xml
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── thealphamerc
│ │ │ │ │ └── flutter_twitter_clone
│ │ │ │ │ └── MainActivity.java
│ │ │ └── AndroidManifest.xml
│ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ └── profile
│ │ │ └── AndroidManifest.xml
│ └── build.gradle
├── .gitignore
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── settings.gradle
└── build.gradle
├── ios
├── Runner
│ ├── Runner-Bridging-Header.h
│ ├── Assets.xcassets
│ │ ├── LaunchImage.imageset
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ ├── README.md
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-50x50@1x.png
│ │ │ ├── Icon-App-50x50@2x.png
│ │ │ ├── Icon-App-57x57@1x.png
│ │ │ ├── Icon-App-57x57@2x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-72x72@1x.png
│ │ │ ├── Icon-App-72x72@2x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ └── Info.plist
├── Flutter
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ ├── Flutter.podspec
│ └── AppFrameworkInfo.plist
├── Runner.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ └── contents.xcworkspacedata
└── Podfile
├── assets
├── fonts
│ ├── icons.ttf
│ ├── HelveticaNeue.ttf
│ ├── HelveticaNeueIt.ttf
│ ├── HelveticaNeue400.ttf
│ ├── HelveticaNeue500.ttf
│ ├── HelveticaNeue600.ttf
│ ├── HelveticaNeue700.ttf
│ ├── HelveticaNeue800.ttf
│ └── HelveticaNeue900.ttf
└── images
│ ├── bulb.png
│ ├── qr.png
│ ├── icon-400.png
│ ├── icon-48.png
│ ├── icon-480.png
│ └── google_logo.png
├── screenshots
├── Auth
│ ├── screenshot_1.jpg
│ ├── screenshot_2.jpg
│ ├── screenshot_3.jpg
│ └── screenshot_4.jpg
├── Chat
│ ├── screenshot_1.jpg
│ ├── screenshot_2.jpg
│ ├── screenshot_3.jpg
│ └── screenshot_4.jpg
├── Home
│ ├── screenshot_1.jpg
│ ├── screenshot_2.jpg
│ ├── screenshot_3.jpg
│ ├── screenshot_4.jpg
│ ├── screenshot_5.jpg
│ ├── screenshot_6.jpg
│ └── screenshot_7.jpg
├── Profile
│ ├── screenshot_1.jpg
│ ├── screenshot_2.jpg
│ ├── screenshot_3.jpg
│ ├── screenshot_4.jpg
│ ├── screenshot_5.jpg
│ ├── screenshot_6.jpg
│ └── screenshot_7.jpg
├── Search
│ ├── screenshot_1.jpg
│ └── screenshot_2.jpg
├── Settings
│ ├── screenshot_1.jpg
│ ├── screenshot_2.jpg
│ ├── screenshot_3.jpg
│ ├── screenshot_4.jpg
│ ├── screenshot_5.jpg
│ ├── screenshot_6.jpg
│ ├── screenshot_7.jpg
│ ├── screenshot_8.jpg
│ ├── screenshot_9.jpg
│ └── screenshot_10.jpg
├── CreateTweet
│ ├── screenshot_1.jpg
│ ├── screenshot_2.jpg
│ ├── screenshot_3.jpg
│ └── screenshot_4.jpg
├── Notification
│ ├── screenshot_1.jpg
│ ├── screenshot_2.jpg
│ ├── screenshot_3.jpg
│ └── screenshot_4.jpg
└── TweetDetail
│ ├── screenshot_1.jpg
│ ├── screenshot_2.jpg
│ ├── screenshot_3.jpg
│ ├── screenshot_4.jpg
│ ├── screenshot_5.jpg
│ ├── screenshot_6.jpg
│ └── screenshot_7.jpg
├── .metadata
├── lib
├── page
│ ├── feed
│ │ └── composeTweet
│ │ │ └── widget
│ │ │ ├── widgetView.dart
│ │ │ ├── composeTweetImage.dart
│ │ │ └── composeBottomIconWidget.dart
│ ├── profile
│ │ ├── follow
│ │ │ ├── followingListPage.dart
│ │ │ └── followerListPage.dart
│ │ ├── widgets
│ │ │ └── tabPainter.dart
│ │ └── profileImageView.dart
│ ├── settings
│ │ ├── widgets
│ │ │ ├── headerWidget.dart
│ │ │ ├── settingsAppbar.dart
│ │ │ └── settingsRowWidget.dart
│ │ ├── accountSettings
│ │ │ ├── proxy
│ │ │ │ └── proxyPage.dart
│ │ │ ├── privacyAndSafety
│ │ │ │ ├── directMessage
│ │ │ │ │ └── directMessage.dart
│ │ │ │ └── privacyAndSafetyPage.dart
│ │ │ ├── contentPrefrences
│ │ │ │ ├── contentPreference.dart
│ │ │ │ └── trends
│ │ │ │ │ └── trendsPage.dart
│ │ │ ├── about
│ │ │ │ └── aboutTwitter.dart
│ │ │ ├── notifications
│ │ │ │ └── notificationPage.dart
│ │ │ ├── accountSettingsPage.dart
│ │ │ └── accessibility
│ │ │ │ └── accessibility.dart
│ │ └── settingsAndPrivacyPage.dart
│ ├── Auth
│ │ ├── widget
│ │ │ └── googleLoginButton.dart
│ │ ├── verifyEmail.dart
│ │ ├── selectAuthMethod.dart
│ │ └── forgetPasswordPage.dart
│ ├── common
│ │ ├── usersListPage.dart
│ │ └── splash.dart
│ ├── search
│ │ └── SearchPage.dart
│ └── message
│ │ ├── conversationInformation
│ │ └── conversationInformation.dart
│ │ └── newMessagePage.dart
├── state
│ └── appState.dart
├── helper
│ ├── enum.dart
│ ├── validator.dart
│ ├── customRoute.dart
│ ├── constant.dart
│ └── theme.dart
├── model
│ ├── notificationModel.dart
│ ├── chatModel.dart
│ ├── feedModel.dart
│ └── user.dart
├── widgets
│ ├── newWidget
│ │ ├── title_text.dart
│ │ ├── rippleButton.dart
│ │ ├── emptyList.dart
│ │ ├── customClipper.dart
│ │ ├── customUrlText.dart
│ │ ├── customProgressbar.dart
│ │ └── customLoader.dart
│ ├── bottomMenuBar
│ │ ├── HalfPainter.dart
│ │ ├── tabItem.dart
│ │ └── bottomMenuBar.dart
│ └── tweet
│ │ └── widgets
│ │ ├── unavailableTweet.dart
│ │ ├── parentTweet.dart
│ │ └── tweetImage.dart
└── main.dart
├── .vscode
└── launch.json
├── .github
├── workflows
│ └── dart.yml
├── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
├── FUNDING.yml
└── pull_request_template.md
├── LICENSE
├── test
├── widget_test.dart
└── helper
│ └── utility_test.dart
├── CHANGELOG.md
├── CONTRIBUTING.md
├── .gitignore
└── pubspec.yaml
/android/settings_aar.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
--------------------------------------------------------------------------------
/assets/fonts/icons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/assets/fonts/icons.ttf
--------------------------------------------------------------------------------
/assets/images/bulb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/assets/images/bulb.png
--------------------------------------------------------------------------------
/assets/images/qr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/assets/images/qr.png
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 |
3 | android.useAndroidX=true
4 | android.enableJetifier=true
5 | android.enableR8=true
6 |
--------------------------------------------------------------------------------
/assets/images/icon-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/assets/images/icon-400.png
--------------------------------------------------------------------------------
/assets/images/icon-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/assets/images/icon-48.png
--------------------------------------------------------------------------------
/assets/images/icon-480.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/assets/images/icon-480.png
--------------------------------------------------------------------------------
/assets/images/google_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/assets/images/google_logo.png
--------------------------------------------------------------------------------
/assets/fonts/HelveticaNeue.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/assets/fonts/HelveticaNeue.ttf
--------------------------------------------------------------------------------
/assets/fonts/HelveticaNeueIt.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/assets/fonts/HelveticaNeueIt.ttf
--------------------------------------------------------------------------------
/assets/fonts/HelveticaNeue400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/assets/fonts/HelveticaNeue400.ttf
--------------------------------------------------------------------------------
/assets/fonts/HelveticaNeue500.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/assets/fonts/HelveticaNeue500.ttf
--------------------------------------------------------------------------------
/assets/fonts/HelveticaNeue600.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/assets/fonts/HelveticaNeue600.ttf
--------------------------------------------------------------------------------
/assets/fonts/HelveticaNeue700.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/assets/fonts/HelveticaNeue700.ttf
--------------------------------------------------------------------------------
/assets/fonts/HelveticaNeue800.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/assets/fonts/HelveticaNeue800.ttf
--------------------------------------------------------------------------------
/assets/fonts/HelveticaNeue900.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/assets/fonts/HelveticaNeue900.ttf
--------------------------------------------------------------------------------
/screenshots/Auth/screenshot_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Auth/screenshot_1.jpg
--------------------------------------------------------------------------------
/screenshots/Auth/screenshot_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Auth/screenshot_2.jpg
--------------------------------------------------------------------------------
/screenshots/Auth/screenshot_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Auth/screenshot_3.jpg
--------------------------------------------------------------------------------
/screenshots/Auth/screenshot_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Auth/screenshot_4.jpg
--------------------------------------------------------------------------------
/screenshots/Chat/screenshot_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Chat/screenshot_1.jpg
--------------------------------------------------------------------------------
/screenshots/Chat/screenshot_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Chat/screenshot_2.jpg
--------------------------------------------------------------------------------
/screenshots/Chat/screenshot_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Chat/screenshot_3.jpg
--------------------------------------------------------------------------------
/screenshots/Chat/screenshot_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Chat/screenshot_4.jpg
--------------------------------------------------------------------------------
/screenshots/Home/screenshot_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Home/screenshot_1.jpg
--------------------------------------------------------------------------------
/screenshots/Home/screenshot_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Home/screenshot_2.jpg
--------------------------------------------------------------------------------
/screenshots/Home/screenshot_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Home/screenshot_3.jpg
--------------------------------------------------------------------------------
/screenshots/Home/screenshot_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Home/screenshot_4.jpg
--------------------------------------------------------------------------------
/screenshots/Home/screenshot_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Home/screenshot_5.jpg
--------------------------------------------------------------------------------
/screenshots/Home/screenshot_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Home/screenshot_6.jpg
--------------------------------------------------------------------------------
/screenshots/Home/screenshot_7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Home/screenshot_7.jpg
--------------------------------------------------------------------------------
/screenshots/Profile/screenshot_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Profile/screenshot_1.jpg
--------------------------------------------------------------------------------
/screenshots/Profile/screenshot_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Profile/screenshot_2.jpg
--------------------------------------------------------------------------------
/screenshots/Profile/screenshot_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Profile/screenshot_3.jpg
--------------------------------------------------------------------------------
/screenshots/Profile/screenshot_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Profile/screenshot_4.jpg
--------------------------------------------------------------------------------
/screenshots/Profile/screenshot_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Profile/screenshot_5.jpg
--------------------------------------------------------------------------------
/screenshots/Profile/screenshot_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Profile/screenshot_6.jpg
--------------------------------------------------------------------------------
/screenshots/Profile/screenshot_7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Profile/screenshot_7.jpg
--------------------------------------------------------------------------------
/screenshots/Search/screenshot_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Search/screenshot_1.jpg
--------------------------------------------------------------------------------
/screenshots/Search/screenshot_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Search/screenshot_2.jpg
--------------------------------------------------------------------------------
/screenshots/Settings/screenshot_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Settings/screenshot_1.jpg
--------------------------------------------------------------------------------
/screenshots/Settings/screenshot_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Settings/screenshot_2.jpg
--------------------------------------------------------------------------------
/screenshots/Settings/screenshot_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Settings/screenshot_3.jpg
--------------------------------------------------------------------------------
/screenshots/Settings/screenshot_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Settings/screenshot_4.jpg
--------------------------------------------------------------------------------
/screenshots/Settings/screenshot_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Settings/screenshot_5.jpg
--------------------------------------------------------------------------------
/screenshots/Settings/screenshot_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Settings/screenshot_6.jpg
--------------------------------------------------------------------------------
/screenshots/Settings/screenshot_7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Settings/screenshot_7.jpg
--------------------------------------------------------------------------------
/screenshots/Settings/screenshot_8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Settings/screenshot_8.jpg
--------------------------------------------------------------------------------
/screenshots/Settings/screenshot_9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Settings/screenshot_9.jpg
--------------------------------------------------------------------------------
/screenshots/Settings/screenshot_10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Settings/screenshot_10.jpg
--------------------------------------------------------------------------------
/screenshots/CreateTweet/screenshot_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/CreateTweet/screenshot_1.jpg
--------------------------------------------------------------------------------
/screenshots/CreateTweet/screenshot_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/CreateTweet/screenshot_2.jpg
--------------------------------------------------------------------------------
/screenshots/CreateTweet/screenshot_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/CreateTweet/screenshot_3.jpg
--------------------------------------------------------------------------------
/screenshots/CreateTweet/screenshot_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/CreateTweet/screenshot_4.jpg
--------------------------------------------------------------------------------
/screenshots/Notification/screenshot_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Notification/screenshot_1.jpg
--------------------------------------------------------------------------------
/screenshots/Notification/screenshot_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Notification/screenshot_2.jpg
--------------------------------------------------------------------------------
/screenshots/Notification/screenshot_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Notification/screenshot_3.jpg
--------------------------------------------------------------------------------
/screenshots/Notification/screenshot_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/Notification/screenshot_4.jpg
--------------------------------------------------------------------------------
/screenshots/TweetDetail/screenshot_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/TweetDetail/screenshot_1.jpg
--------------------------------------------------------------------------------
/screenshots/TweetDetail/screenshot_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/TweetDetail/screenshot_2.jpg
--------------------------------------------------------------------------------
/screenshots/TweetDetail/screenshot_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/TweetDetail/screenshot_3.jpg
--------------------------------------------------------------------------------
/screenshots/TweetDetail/screenshot_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/TweetDetail/screenshot_4.jpg
--------------------------------------------------------------------------------
/screenshots/TweetDetail/screenshot_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/TweetDetail/screenshot_5.jpg
--------------------------------------------------------------------------------
/screenshots/TweetDetail/screenshot_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/TweetDetail/screenshot_6.jpg
--------------------------------------------------------------------------------
/screenshots/TweetDetail/screenshot_7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/screenshots/TweetDetail/screenshot_7.jpg
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | *.class
3 | .gradle
4 | /local.properties
5 | /.idea/workspace.xml
6 | /.idea/libraries
7 | .DS_Store
8 | /build
9 | /captures
10 | GeneratedPluginRegistrant.java
11 | /app/google-services.json
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheGithubMafia/chandni2428_79256f12-cfde-47fe-871b-0869f63ed81b/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/thealphamerc/flutter_twitter_clone/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.thealphamerc.flutter_twitter_clone;
2 |
3 | import io.flutter.embedding.android.FlutterActivity;
4 |
5 | public class MainActivity extends FlutterActivity {
6 | }
7 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
7 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 68587a0916366e9512a78df22c44163d041dd5f3
8 | channel: unknown
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/lib/page/feed/composeTweet/widget/widgetView.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | abstract class WidgetView extends StatelessWidget {
4 | const WidgetView(this.state, {Key key}) : super(key: key);
5 |
6 | final T2 state;
7 |
8 | T1 get widget => (state as State).widget as T1;
9 |
10 | @override
11 | Widget build(BuildContext context);
12 | }
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/lib/state/appState.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class AppState extends ChangeNotifier{
4 |
5 | bool _isBusy;
6 | bool get isbusy => _isBusy;
7 | set loading(bool value){
8 | _isBusy = value;
9 | notifyListeners();
10 | }
11 | int _pageIndex = 0;
12 | int get pageIndex {
13 | return _pageIndex;
14 | }
15 | set setpageIndex(int index){
16 | _pageIndex = index;
17 | notifyListeners();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Dart",
9 | "type": "dart",
10 | "request": "launch",
11 | "program": "lib/main.dart"
12 | },
13 | ]
14 | }
--------------------------------------------------------------------------------
/lib/helper/enum.dart:
--------------------------------------------------------------------------------
1 | enum AuthStatus {
2 | NOT_DETERMINED,
3 | NOT_LOGGED_IN,
4 | LOGGED_IN,
5 | }
6 | enum TweetType{
7 | Tweet,
8 | Detail,
9 | Reply,
10 | ParentTweet
11 | }
12 |
13 | enum SortUser{
14 | ByVerified,
15 | ByAlphabetically,
16 | ByNewest,
17 | ByOldest,
18 | ByMaxFollower
19 | }
20 |
21 | enum NotificationType{
22 | NOT_DETERMINED,
23 | Message,
24 | Tweet,
25 | Reply,
26 | Retweet,
27 | Follow,
28 | Mention,
29 | Like
30 | }
--------------------------------------------------------------------------------
/.github/workflows/dart.yml:
--------------------------------------------------------------------------------
1 | name: Dart CI
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build-and-test:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v1
10 | - uses: actions/setup-java@v1
11 | with:
12 | java-version: '12.x'
13 | - uses: subosito/flutter-action@v1
14 | with:
15 | channel: 'stable'
16 | # Get flutter packages
17 | - run: flutter pub get
18 | # Build :D
19 | - run: flutter build aot
20 |
--------------------------------------------------------------------------------
/lib/model/notificationModel.dart:
--------------------------------------------------------------------------------
1 | class NotificationModel {
2 | String tweetKey;
3 | String updatedAt;
4 | String type;
5 |
6 | NotificationModel({
7 | this.tweetKey,
8 | });
9 |
10 | NotificationModel.fromJson(Map json, ) {
11 | // tweetKey = tweetId;
12 | this.updatedAt = json["updatedAt"];
13 | this.type = json["type"];
14 | }
15 |
16 | Map toJson() => {
17 | "tweetKey": tweetKey == null ? null : tweetKey,
18 | };
19 | }
20 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 | import Firebase
4 |
5 | @UIApplicationMain
6 | @objc class AppDelegate: FlutterAppDelegate {
7 | override func application(
8 | _ application: UIApplication,
9 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
10 | ) -> Bool {
11 | FirebaseApp.configure()
12 | GeneratedPluginRegistrant.register(with: self)
13 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.5.0'
9 | classpath 'com.google.gms:google-services:4.3.4'
10 | }
11 | }
12 |
13 | allprojects {
14 | repositories {
15 | google()
16 | jcenter()
17 | }
18 | }
19 |
20 | rootProject.buildDir = '../build'
21 | subprojects {
22 | project.buildDir = "${rootProject.buildDir}/${project.name}"
23 | }
24 | subprojects {
25 | project.evaluationDependsOn(':app')
26 | }
27 |
28 | task clean(type: Delete) {
29 | delete rootProject.buildDir
30 | }
31 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: ['https://www.paypal.me/shubhamsinghchahar']
13 |
--------------------------------------------------------------------------------
/ios/Flutter/Flutter.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # NOTE: This podspec is NOT to be published. It is only used as a local source!
3 | #
4 |
5 | Pod::Spec.new do |s|
6 | s.name = 'Flutter'
7 | s.version = '1.0.0'
8 | s.summary = 'High-performance, high-fidelity mobile apps.'
9 | s.description = <<-DESC
10 | Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS.
11 | DESC
12 | s.homepage = 'https://flutter.io'
13 | s.license = { :type => 'MIT' }
14 | s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
15 | s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
16 | s.ios.deployment_target = '8.0'
17 | s.vendored_frameworks = 'Flutter.framework'
18 | end
19 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Smartphone (please complete the following information):**
27 | - Device: [e.g. iPhone6]
28 | - OS: [e.g. iOS8.1]
29 | - Version [e.g. 22]
30 |
31 | **App**
32 | - version[e.g. 1.0.4]
33 |
34 | **Additional context**
35 | Add any other context about the problem here.
36 |
--------------------------------------------------------------------------------
/lib/page/profile/follow/followingListPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/constant.dart';
3 | import 'package:flutter_twitter_clone/page/common/usersListPage.dart';
4 | import 'package:flutter_twitter_clone/state/authState.dart';
5 | import 'package:provider/provider.dart';
6 |
7 | class FollowingListPage extends StatelessWidget {
8 | @override
9 | Widget build(BuildContext context) {
10 | var state = Provider.of(context);
11 | return UsersListPage(
12 | pageTitle: 'Following',
13 | userIdsList: state.profileUserModel.followingList,
14 | appBarIcon: AppIcon.follow,
15 | emptyScreenText:
16 | '${state?.profileUserModel?.userName ?? state.userModel.userName} isn\'t follow anyone',
17 | emptyScreenSubTileText: 'When they do they\'ll be listed here.');
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/widgets/newWidget/title_text.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:google_fonts/google_fonts.dart';
3 |
4 | class TitleText extends StatelessWidget {
5 | final String text;
6 | final double fontSize;
7 | final Color color;
8 | final FontWeight fontWeight;
9 | final TextAlign textAlign;
10 | final TextOverflow overflow;
11 | const TitleText(
12 | this.text, {
13 | Key key,
14 | this.fontSize = 18,
15 | this.color = Colors.black,
16 | this.fontWeight = FontWeight.w800,
17 | this.textAlign = TextAlign.left,
18 | this.overflow = TextOverflow.visible,
19 | }) : super(key: key);
20 | @override
21 | Widget build(BuildContext context) {
22 | return Text(
23 | text,
24 | style: GoogleFonts.muli(
25 | fontSize: fontSize,
26 | fontWeight: fontWeight,
27 | color: color,
28 | ),
29 | textAlign: textAlign,
30 | overflow: overflow,
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 |
7 |
8 | ## What does this PR accomplish?
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ## Did you add any dependencies?
17 |
18 |
19 |
20 | ## How did you test the change?
21 |
22 |
23 |
--------------------------------------------------------------------------------
/lib/page/settings/widgets/headerWidget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/widgets/newWidget/customUrlText.dart';
4 |
5 | class HeaderWidget extends StatelessWidget {
6 | final String title;
7 | final bool secondHeader;
8 | const HeaderWidget(this.title,{Key key, this.secondHeader = false}) : super(key: key);
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Container(
13 | padding: secondHeader ? EdgeInsets.only(left: 18, right: 18, bottom: 10, top: 35) : EdgeInsets.symmetric(horizontal: 18, vertical: 12),
14 | color: TwitterColor.mystic,
15 | alignment: Alignment.centerLeft,
16 | child: UrlText(
17 | text: title ?? '',
18 | style: TextStyle(
19 | fontSize: 20,
20 | color: AppColor.darkGrey,
21 | fontWeight: FontWeight.w700),
22 | ),
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/page/profile/follow/followerListPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/constant.dart';
3 | import 'package:flutter_twitter_clone/page/common/usersListPage.dart';
4 | import 'package:flutter_twitter_clone/state/authState.dart';
5 | import 'package:provider/provider.dart';
6 |
7 | class FollowerListPage extends StatelessWidget {
8 | FollowerListPage({Key key}) : super(key: key);
9 | @override
10 | Widget build(BuildContext context) {
11 | var state = Provider.of(context, listen: false);
12 | return UsersListPage(
13 | pageTitle: 'Followers',
14 | userIdsList: state.profileUserModel?.followersList,
15 | appBarIcon: AppIcon.follow,
16 | emptyScreenText:
17 | '${state?.profileUserModel?.userName ?? state.userModel.userName} doesn\'t have any followers',
18 | emptyScreenSubTileText:
19 | 'When someone follow them, they\'ll be listed here.',
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/lib/helper/validator.dart:
--------------------------------------------------------------------------------
1 |
2 | class Validator {
3 | bool _isNumeric(String s) {
4 | for (int i = 0; i < s.length; i++) {
5 | if (double.tryParse(s[i]) != null) {
6 | return true;
7 | }
8 | }
9 | return false;
10 | }
11 |
12 | String validateEmail(String s) {
13 | Pattern pattern =
14 | r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
15 | RegExp regex = new RegExp(pattern);
16 | if (!regex.hasMatch(s)) {
17 | return 'Please enter an email!';
18 | } else {
19 | return null;
20 | }
21 | }
22 |
23 | String validateName(String s) {
24 | if (_isNumeric(s)) {
25 | return 'Invalid Name!';
26 | }
27 | if (s.isEmpty) {
28 | return 'Don\'t forget your name!';
29 | }
30 | return null;
31 | }
32 |
33 | String validatePassword(String s) {
34 | if (s.isEmpty) {
35 | return 'Gotta be secure, enter a password!';
36 | }
37 | return null;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Sonu Sharma
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/lib/widgets/newWidget/rippleButton.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 |
4 | class RippleButton extends StatelessWidget {
5 | final Widget child;
6 | final Function onPressed;
7 | final BorderRadius borderRadius;
8 | final Color splashColor;
9 | RippleButton({Key key, this.child, this.onPressed, this.borderRadius = const BorderRadius.all(Radius.circular(0)), this.splashColor})
10 | : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Stack(
15 | children: [
16 | child,
17 | Positioned(
18 | left: 0,
19 | right: 0,
20 | top: 0,
21 | bottom: 0,
22 | child: FlatButton(
23 | splashColor: splashColor,
24 | shape: RoundedRectangleBorder(
25 | borderRadius: borderRadius
26 | ),
27 | onPressed: () {
28 | if (onPressed != null) {
29 | onPressed();
30 | }
31 | },
32 | child: Container()),
33 | )
34 | ],
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/page/settings/widgets/settingsAppbar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
4 |
5 | class SettingsAppBar extends StatelessWidget implements PreferredSizeWidget {
6 | SettingsAppBar({Key key, this.title, this.subtitle}) : super(key: key);
7 | final String title, subtitle;
8 | final Size appBarHeight = Size.fromHeight(60.0);
9 | @override
10 | Widget build(BuildContext context) {
11 | return AppBar(
12 | title: Column(
13 | crossAxisAlignment: CrossAxisAlignment.start,
14 | mainAxisAlignment: MainAxisAlignment.center,
15 | children: [
16 | SizedBox(height: 5),
17 | customTitleText(
18 | title,
19 | ),
20 | Text(
21 | subtitle ?? '',
22 | style: TextStyle(color: AppColor.darkGrey, fontSize: 18),
23 | )
24 | ],
25 | ),
26 | iconTheme: IconThemeData(color: Colors.blue),
27 | backgroundColor: Colors.white,
28 | );
29 | }
30 |
31 | @override
32 | Size get preferredSize => appBarHeight;
33 | }
34 |
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_test/flutter_test.dart';
10 |
11 | import 'package:flutter_twitter_clone/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(MyApp());
17 |
18 | // Verify that our counter starts at 0.
19 | expect(find.text('0'), findsOneWidget);
20 | expect(find.text('1'), findsNothing);
21 |
22 | // Tap the '+' icon and trigger a frame.
23 | await tester.tap(find.byIcon(Icons.add));
24 | await tester.pump();
25 |
26 | // Verify that our counter has incremented.
27 | expect(find.text('0'), findsNothing);
28 | expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/lib/model/chatModel.dart:
--------------------------------------------------------------------------------
1 | class ChatMessage {
2 | String key;
3 | String senderId;
4 | String message;
5 | bool seen;
6 | String createdAt;
7 | String timeStamp;
8 |
9 |
10 | String senderName;
11 | String receiverId;
12 |
13 | ChatMessage({
14 | this.key,
15 | this.senderId,
16 | this.message,
17 | this.seen,
18 | this.createdAt,
19 | this.receiverId,
20 | this.senderName,
21 | this.timeStamp
22 | });
23 |
24 | factory ChatMessage.fromJson(Map json) => ChatMessage(
25 | key: json["key"],
26 | senderId: json["sender_id"],
27 | message: json["message"],
28 | seen: json["seen"],
29 | createdAt: json["created_at"],
30 | timeStamp:json['timeStamp'],
31 | senderName: json["senderName"],
32 | receiverId: json["receiverId"]
33 | );
34 |
35 | Map toJson() => {
36 | "key": key,
37 | "sender_id": senderId,
38 | "message": message,
39 | "receiverId": receiverId,
40 | "seen": seen,
41 | "created_at": createdAt,
42 | "senderName": senderName,
43 | "timeStamp":timeStamp
44 | };
45 | }
46 |
--------------------------------------------------------------------------------
/lib/page/profile/widgets/tabPainter.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 |
4 | class TabIndicator extends Decoration {
5 | final BoxPainter _painter;
6 |
7 | TabIndicator() : _painter = _TabPainter();
8 |
9 | @override
10 | BoxPainter createBoxPainter([onChanged]) => _painter;
11 | }
12 |
13 | class _TabPainter extends BoxPainter {
14 | @override
15 | void paint(Canvas canvas, Offset offset, ImageConfiguration cfg) {
16 | final Offset blueLineOffset1 = offset + Offset(0, cfg.size.height);
17 | final Offset greyLineOffset2 = Offset(0, cfg.size.height + 1);
18 |
19 | final Offset blueLinePaint2 =
20 | offset + Offset(cfg.size.width, cfg.size.height);
21 | final Offset greyLineOffset1 =
22 | offset + Offset(cfg.size.width * 3, cfg.size.height + 1);
23 |
24 | var blueLinePaint = Paint()
25 | ..color = TwitterColor.dodgetBlue
26 | ..strokeWidth = 2;
27 | var greyLinePaint = Paint()
28 | ..color = AppColor.lightGrey
29 | ..strokeWidth = .2;
30 |
31 | canvas.drawLine(greyLineOffset1, greyLineOffset2, greyLinePaint);
32 | canvas.drawLine(blueLineOffset1, blueLinePaint2, blueLinePaint);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/widgets/bottomMenuBar/HalfPainter.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:vector_math/vector_math.dart';
3 | import 'dart:io';
4 |
5 | class HalfPainter extends CustomPainter {
6 | HalfPainter(Color paintColor) {
7 | this.arcPaint = Paint()..color = paintColor;
8 | }
9 |
10 | Paint arcPaint;
11 |
12 | @override
13 | void paint(Canvas canvas, Size size) {
14 | final Rect largeRect = Rect.fromLTWH(10, 0, size.width - 20, 70);
15 | final Rect beforeRect = Rect.fromLTWH(0, (size.height / 2) - 9, 10, 10);
16 | final Rect afterRect = Rect.fromLTWH(size.width - 10, (size.height / 2) - 9, 10, 10);
17 |
18 | final path = Path();
19 | if(Platform.isAndroid){
20 | path.arcTo(beforeRect, radians(0), radians(90), false);
21 | path.lineTo(20, size.height / 2);
22 | path.arcTo(largeRect, radians(0), -radians(180), false);
23 | path.moveTo(size.width - 10, size.height / 2);
24 | path.lineTo(size.width - 10, (size.height / 2) - 10);
25 | path.arcTo(afterRect, radians(180), radians(-90), false);
26 | path.close();
27 | }
28 |
29 |
30 | canvas.drawPath(path, arcPaint);
31 | }
32 |
33 | @override
34 | bool shouldRepaint(CustomPainter oldDelegate) {
35 | return true;
36 | }
37 | }
--------------------------------------------------------------------------------
/lib/helper/customRoute.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/routes.dart';
3 |
4 | class CustomRoute extends MaterialPageRoute {
5 | CustomRoute({WidgetBuilder builder, RouteSettings settings})
6 | : super(builder: builder, settings: settings);
7 |
8 | @override
9 | Widget buildTransitions(BuildContext context, Animation animation,
10 | Animation secondaryAnimation, Widget child) {
11 | Routes.sendNavigationEventToFirebase(settings.name);
12 |
13 | return FadeTransition(
14 | opacity: CurvedAnimation(parent: animation, curve: Curves.fastOutSlowIn),
15 | child: child,
16 | );
17 | }
18 | }
19 |
20 | class SlideLeftRoute extends MaterialPageRoute {
21 | SlideLeftRoute({WidgetBuilder builder, RouteSettings settings})
22 | : super(builder: builder, settings: settings);
23 | @override
24 | Widget buildTransitions(BuildContext context, Animation animation,
25 | Animation secondaryAnimation, Widget child) {
26 | Routes.sendNavigationEventToFirebase(settings.name);
27 |
28 | return SlideTransition(
29 | position: new Tween(
30 | begin: const Offset(1.0, 0.0),
31 | end: Offset.zero,
32 | ).animate(
33 | CurvedAnimation(parent: animation, curve: Curves.fastOutSlowIn)),
34 | child: child,
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/widgets/newWidget/emptyList.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/widgets/newWidget/title_text.dart';
4 | import '../customWidgets.dart';
5 |
6 | class EmptyList extends StatelessWidget {
7 | EmptyList(this.title, {this.subTitle});
8 |
9 | final String subTitle;
10 | final String title;
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Container(
15 | height: fullHeight(context) - 135,
16 | color: TwitterColor.mystic,
17 | child: NotifyText(title: title,subTitle: subTitle,)
18 | );
19 | }
20 | }
21 |
22 | class NotifyText extends StatelessWidget {
23 | final String subTitle;
24 | final String title;
25 | const NotifyText({Key key, this.subTitle, this.title}) : super(key: key);
26 |
27 | @override
28 | Widget build(BuildContext context) {
29 | return Column(
30 | mainAxisSize: MainAxisSize.max,
31 | mainAxisAlignment: MainAxisAlignment.center,
32 | children: [
33 | TitleText(title, fontSize: 20, textAlign: TextAlign.center),
34 | SizedBox(
35 | height: 20,
36 | ),
37 | TitleText(
38 | subTitle,
39 | fontSize: 16,
40 | fontWeight: FontWeight.w500,
41 | color: AppColor.darkGrey,
42 | textAlign: TextAlign.center,
43 | ),
44 | ],
45 | );
46 | }
47 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [1.0.6] - UPCOMING
2 |
3 | * Three tabs are added to filter tweet and commnet tweet and tweet with media on profile page.
4 | * User profile pic view added to view profile picture of any user.
5 | * User can tag other users in tweet, comment and in retweet.
6 | * A notification will send to you if someone tag you in a tweet.
7 | * After tapping on notification from system notification tray, you will redirect to user profile who tagged you.
8 | * You can check the tweet on his profile.
9 |
10 | ## [1.0.5] - 15 Apr 2020
11 |
12 | * Notification on chat message in system tray.
13 | * Now if user click on comment Tweet it's parent tweet will visible in detail.
14 | * Google login button added on signup page.
15 | * Null value alert issue on forgot password fixed
16 | * Hash tags font weight and size issue fixed.
17 |
18 | ## [1.0.4] - 04 Apr 2020
19 |
20 | * User sort feature added on user search page.
21 | * Added pull to refresh on search page.
22 | * Newest Tweet will show first in Tweet list.
23 | * Newest comment tweet will show first in comment Tweet list.
24 |
25 | ## [1.0.3] - 31 Mar 2020
26 |
27 | * Google login failed bug fix
28 | * Email login at first time bug fix.
29 |
30 | ## [1.0.2] - 30 Mar 2020
31 |
32 | * Added users list who liked tweet.
33 | * User can view nested profile view.
34 | * User can view their following and follower's profile.
35 | * Bug fix and performance improvement.
36 |
37 | ## [1.0.1] - 27 Mar 2020
38 |
39 | * Added Retweet functionality.
40 | * Show Retweet count on tweet.
41 |
42 | ## [1.0.0] - 22 Mar 2020
43 |
44 | * Initials Launch
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/page/settings/accountSettings/proxy/proxyPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/page/settings/widgets/headerWidget.dart';
4 | import 'package:flutter_twitter_clone/page/settings/widgets/settingsRowWidget.dart';
5 | import 'package:flutter_twitter_clone/widgets/customAppBar.dart';
6 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
7 | import 'package:flutter_twitter_clone/widgets/newWidget/title_text.dart';
8 |
9 | class ProxyPage extends StatelessWidget {
10 | const ProxyPage({Key key}) : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Scaffold(
15 | backgroundColor: TwitterColor.white,
16 | appBar: CustomAppBar(
17 | isBackButton: true,
18 | title: customTitleText(
19 | 'Proxy',
20 | ),
21 | ),
22 | body: ListView(
23 | physics: BouncingScrollPhysics(),
24 | children: [
25 | SettingRowWidget(
26 | "Enable HTTP Proxy",
27 | showCheckBox: true,
28 | vPadding: 15,
29 | showDivider: true,
30 | subtitle:
31 | 'Configure HTTP proxy for network request (note: this does not apply to browser).',
32 | ),
33 | SettingRowWidget(
34 | "Proxy Host",
35 | subtitle: 'Configure your proxy\'s hostname.',
36 | showDivider: true,
37 | ),
38 | SettingRowWidget(
39 | "Proxy Port",
40 | subtitle: 'Configure your proxy\'s port number.',
41 | ),
42 | ],
43 | ),
44 | );
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/widgets/tweet/widgets/unavailableTweet.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/enum.dart';
3 | import 'package:flutter_twitter_clone/helper/theme.dart';
4 | import 'package:flutter_twitter_clone/model/feedModel.dart';
5 |
6 | class UnavailableTweet extends StatelessWidget {
7 | const UnavailableTweet({Key key, this.snapshot, this.type}) : super(key: key);
8 |
9 | final AsyncSnapshot snapshot;
10 | final TweetType type;
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return AnimatedContainer(
15 | duration: Duration(milliseconds: 500),
16 | height: 40,
17 | padding: EdgeInsets.symmetric(horizontal: 16),
18 | margin: EdgeInsets.only(
19 | right: 16,
20 | top: 5,
21 | left: type == TweetType.Tweet || type == TweetType.ParentTweet
22 | ? 70
23 | : 16),
24 | alignment: Alignment.centerLeft,
25 | decoration: BoxDecoration(
26 | color: AppColor.extraLightGrey.withOpacity(.3),
27 | border: Border.all(color: AppColor.extraLightGrey, width: .5),
28 | borderRadius: BorderRadius.all(Radius.circular(10)),
29 | ),
30 | child: snapshot.connectionState == ConnectionState.waiting
31 | ? SizedBox(
32 | height: 2,
33 | child: LinearProgressIndicator(
34 | backgroundColor: AppColor.extraLightGrey,
35 | valueColor: AlwaysStoppedAnimation(
36 | AppColor.darkGrey.withOpacity(.3),
37 | ),
38 | ),
39 | )
40 | : Text('This quoted Tweet is unavailable', style: userNameStyle),
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:firebase_core/firebase_core.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_twitter_clone/helper/theme.dart';
4 | import 'package:flutter_twitter_clone/state/chats/chatUserState.dart';
5 | import 'package:flutter_twitter_clone/state/searchState.dart';
6 | import 'helper/routes.dart';
7 | import 'state/appState.dart';
8 | import 'package:provider/provider.dart';
9 | import 'state/authState.dart';
10 | import 'state/feedState.dart';
11 | import 'package:google_fonts/google_fonts.dart';
12 |
13 | import 'state/notificationState.dart';
14 |
15 | void main() async {
16 | WidgetsFlutterBinding.ensureInitialized();
17 | await Firebase.initializeApp();
18 | runApp(MyApp());
19 | }
20 |
21 | class MyApp extends StatelessWidget {
22 | @override
23 | Widget build(BuildContext context) {
24 | return MultiProvider(
25 | providers: [
26 | ChangeNotifierProvider(create: (_) => AppState()),
27 | ChangeNotifierProvider(create: (_) => AuthState()),
28 | ChangeNotifierProvider(create: (_) => FeedState()),
29 | ChangeNotifierProvider(create: (_) => ChatUserState()),
30 | ChangeNotifierProvider(create: (_) => SearchState()),
31 | ChangeNotifierProvider(
32 | create: (_) => NotificationState()),
33 | ],
34 | child: MaterialApp(
35 | title: 'Fwitter',
36 | theme: AppTheme.apptheme.copyWith(
37 | textTheme: GoogleFonts.muliTextTheme(
38 | Theme.of(context).textTheme,
39 | ),
40 | ),
41 | debugShowCheckedModeBanner: false,
42 | routes: Routes.route(),
43 | onGenerateRoute: (settings) => Routes.onGenerateRoute(settings),
44 | onUnknownRoute: (settings) => Routes.onUnknownRoute(settings),
45 | ),
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/test/helper/utility_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_twitter_clone/helper/utility.dart';
2 | import 'package:test/test.dart';
3 |
4 | void main() {
5 | group("Check Date time", () {
6 | test('Check post time', () {
7 | var date = DateTime.now().toUtc();
8 | var now = getChatTime(date.toString());
9 | expect(now, "now");
10 |
11 | var sec = getChatTime(date.add(Duration(seconds: -8)).toString());
12 | expect(sec, "8 s");
13 |
14 | var min = getChatTime(date.add(Duration(minutes: -8)).toString());
15 | expect(min, "8 m");
16 |
17 | var hour = getChatTime(date.add(Duration(hours: -8)).toString());
18 | expect(hour, "8 h");
19 |
20 | var yesterday = getChatTime(date.add(Duration(days: -1)).toString());
21 | expect(yesterday, "yesterday");
22 |
23 | var randomDate = getChatTime("2020-03-19T14:12:46.286410");
24 | expect(randomDate, "19 Mar");
25 | });
26 |
27 | test('Check Social Links', () {
28 | var url1 = getSocialLinks("google.com");
29 | expect(url1, "https://www.google.com");
30 |
31 | var url2 = getSocialLinks("www.google.com");
32 | expect(url2, "https://www.google.com");
33 |
34 | var url3 = getSocialLinks("http://www.google.com");
35 | expect(url3, "http://www.google.com");
36 |
37 | var url4 = getSocialLinks("https://www.google.com");
38 | expect(url4, "https://www.google.com");
39 | });
40 |
41 | test("Validate Email", () {
42 | final email1 = validateEmal("test@gmail.com");
43 | expect(true, email1);
44 |
45 | final email2 = validateEmal("test@gmail.com.com");
46 | expect(true, email2);
47 |
48 | final email3 = validateEmal("test@gmailcom");
49 | expect(false, email3);
50 |
51 | final email4 = validateEmal("testgmail.com");
52 | expect(false, email4);
53 |
54 | final email5 = validateEmal("@testgmail.com");
55 | expect(false, email5);
56 | });
57 | });
58 | }
59 |
--------------------------------------------------------------------------------
/lib/page/feed/composeTweet/widget/composeTweetImage.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
5 |
6 | class ComposeTweetImage extends StatelessWidget {
7 | final File image;
8 | final Function onCrossIconPressed;
9 | const ComposeTweetImage({Key key, this.image, this.onCrossIconPressed})
10 | : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Container(
15 | child: image == null
16 | ? Container()
17 | : Stack(
18 | children: [
19 | Container(
20 | alignment: Alignment.topRight,
21 | child: Container(
22 | height: 220,
23 | width: fullWidth(context) * .8,
24 | decoration: BoxDecoration(
25 | borderRadius: BorderRadius.all(Radius.circular(10)),
26 | image: DecorationImage(
27 | image: FileImage(image), fit: BoxFit.cover),
28 | ),
29 | ),
30 | ),
31 | Align(
32 | alignment: Alignment.topRight,
33 | child: Container(
34 | padding: EdgeInsets.all(0),
35 | decoration: BoxDecoration(
36 | shape: BoxShape.circle, color: Colors.black54),
37 | child: IconButton(
38 | padding: EdgeInsets.all(0),
39 | iconSize: 20,
40 | onPressed: onCrossIconPressed,
41 | icon: Icon(
42 | Icons.close,
43 | color: Theme.of(context).colorScheme.onPrimary,
44 | ),
45 | ),
46 | ),
47 | )
48 | ],
49 | ),
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/widgets/tweet/widgets/parentTweet.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/enum.dart';
3 | import 'package:flutter_twitter_clone/model/feedModel.dart';
4 | import 'package:flutter_twitter_clone/state/feedState.dart';
5 | import 'package:flutter_twitter_clone/widgets/tweet/tweet.dart';
6 | import 'package:flutter_twitter_clone/widgets/tweet/widgets/unavailableTweet.dart';
7 | import 'package:provider/provider.dart';
8 |
9 | class ParentTweetWidget extends StatelessWidget {
10 | ParentTweetWidget(
11 | {Key key, this.childRetwetkey, this.type, this.isImageAvailable, this.trailing})
12 | : super(key: key);
13 |
14 | final String childRetwetkey;
15 | final TweetType type;
16 | final Widget trailing;
17 | final bool isImageAvailable;
18 |
19 | void onTweetPressed(BuildContext context, FeedModel model) {
20 | var feedstate = Provider.of(context, listen: false);
21 | feedstate.getpostDetailFromDatabase(null, model: model);
22 | Navigator.of(context).pushNamed('/FeedPostDetail/' + model.key);
23 | }
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | var feedstate = Provider.of(context, listen: false);
28 | return FutureBuilder(
29 | future: feedstate.fetchTweet(childRetwetkey),
30 | builder: (context, AsyncSnapshot snapshot) {
31 | if (snapshot.hasData) {
32 | return Tweet(
33 | model: snapshot.data,
34 | type: TweetType.ParentTweet,
35 | trailing:trailing
36 | );
37 | }
38 | if ((snapshot.connectionState == ConnectionState.done ||
39 | snapshot.connectionState == ConnectionState.waiting) &&
40 | !snapshot.hasData) {
41 | return UnavailableTweet(
42 | snapshot: snapshot,
43 | type: type,
44 | );
45 | } else {
46 | return SizedBox.shrink();
47 | }
48 | },
49 | );
50 | }
51 | }
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing Guide
2 |
3 | Fwitter app is Open Source! I love it when people contribute!
4 |
5 | ## Getting Started
6 |
7 | - Make sure you have a [GitHub Account](https://github.com/signup/free).
8 | - Make sure the [Dart SDK](https://www.dartlang.org/tools/sdk/) is installed on your system.
9 | - Make sure you have [Git](http://git-scm.com/) installed on your system.
10 | - [Fork](https://help.github.com/articles/fork-a-repo) the [repository](https://github.com/SpinlockLabs/github.dart) on GitHub.
11 |
12 | ## Making Changes
13 |
14 | - [Create a branch](https://help.github.com/articles/creating-and-deleting-branches-within-your-repository) for your changes.
15 | - [Commit your code](http://git-scm.com/book/en/Git-Basics-Recording-Changes-to-the-Repository) for each logical change (see [tips for creating better commit messages](http://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message)).
16 | - [Push your change](https://help.github.com/articles/pushing-to-a-remote) to your fork.
17 | - [Create a Pull Request](https://help.github.com/articles/creating-a-pull-request) on GitHub for your change.
18 | - Wait for reviewers to give feedback.
19 | - When the reviewers think that the Pull Request is ready, they will merge it.
20 |
21 | ## Code Style
22 |
23 | Fwitter follows the [Dart Style Guide](https://www.dartlang.org/articles/style-guide/). Please note that if your code is not formatted according to the guide as much as possible, we will reject your Pull Request until it is fixed. Some things such as long lines will generally be accepted, however try to make it smaller if possible.
24 |
25 | ## Efficiency
26 |
27 | Fwitter is committed to efficiency as much as possible. If your code is not efficient, then we will probably reject your Pull Request.
28 |
29 | ## Rejections
30 |
31 | Pull Request rejections are not a bad thing. It just means you need to fix something. Perhaps it is important to define 'rejection' as it is used in this case. A rejection is when a Fwitter committer comments on a Pull Request with a comment like 'rejected due to incorrect formatting'.
32 |
33 | ## Contacting Us
34 |
35 | - Email: `sonu.sharma045@gmail.com`
36 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
26 |
27 | android {
28 | compileSdkVersion 29
29 |
30 | lintOptions {
31 | disable 'InvalidPackage'
32 | }
33 |
34 | defaultConfig {
35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
36 | applicationId "com.thealphamerc.flutter_twitter_clone_dev"
37 | minSdkVersion 16
38 | targetSdkVersion 29
39 | versionCode flutterVersionCode.toInteger()
40 | versionName flutterVersionName
41 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
42 | multiDexEnabled true
43 | }
44 |
45 | buildTypes {
46 | release {
47 | // TODO: Add your own signing config for the release build.
48 | // Signing with the debug keys for now, so `flutter run --release` works.
49 | signingConfig signingConfigs.debug
50 | }
51 | }
52 | }
53 |
54 | flutter {
55 | source '../..'
56 | }
57 |
58 | dependencies {
59 | testImplementation 'junit:junit:4.12'
60 | androidTestImplementation 'androidx.test:runner:1.1.1'
61 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
62 | implementation 'com.android.support:multidex:1.0.3'
63 | }
64 | apply plugin: 'com.google.gms.google-services'
65 |
--------------------------------------------------------------------------------
/lib/page/settings/accountSettings/privacyAndSafety/directMessage/directMessage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/model/user.dart';
4 | import 'package:flutter_twitter_clone/page/settings/widgets/headerWidget.dart';
5 | import 'package:flutter_twitter_clone/page/settings/widgets/settingsAppbar.dart';
6 | import 'package:flutter_twitter_clone/page/settings/widgets/settingsRowWidget.dart';
7 | import 'package:flutter_twitter_clone/state/authState.dart';
8 | import 'package:flutter_twitter_clone/widgets/customAppBar.dart';
9 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
10 | import 'package:provider/provider.dart';
11 |
12 | class DirectMessagesPage extends StatelessWidget {
13 | const DirectMessagesPage({Key key}) : super(key: key);
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | var user = Provider.of(context).userModel ?? UserModel();
18 | return Scaffold(
19 | backgroundColor: TwitterColor.white,
20 | appBar: SettingsAppBar(
21 | title: 'Direct Messages',
22 | subtitle: user.userName,
23 | ),
24 | body: ListView(
25 | physics: BouncingScrollPhysics(),
26 | children: [
27 | HeaderWidget(
28 | 'Direct Messages',
29 | secondHeader: true,
30 | ),
31 | SettingRowWidget(
32 | "Receive message requests",
33 | navigateTo: null,
34 | showDivider: false,
35 | visibleSwitch: true,
36 | vPadding: 20,
37 | subtitle:
38 | 'You will be able to receive Direct Message requests from anyone on Fwitter, even if you don\'t follow them.',
39 | ),
40 | SettingRowWidget(
41 | "Show read receipts",
42 | navigateTo: null,
43 | showDivider: false,
44 | visibleSwitch: true,
45 | subtitle:
46 | 'When someone sends you a message, people in the conversation will know you\'ve seen it. If you turn off this setting, you won\'t be able to see read receipt from others.',
47 | ),
48 | ],
49 | ),
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/widgets/newWidget/customClipper.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class WavyHeaderImage extends StatefulWidget {
4 | final Widget child;
5 |
6 | const WavyHeaderImage({Key key, this.child}) : super(key: key);
7 | @override
8 | State createState() {
9 | return _WavyHeaderState();
10 | }
11 |
12 | }
13 | class _WavyHeaderState extends State{
14 | @override
15 | Widget build(BuildContext context) {
16 | return ClipPath(
17 | child:widget.child,// Container(height:fullHeight(context),width: fullWidth(context),color:Colors.grey.shade100,),
18 | clipper: BottomWaveClipper(),
19 | );
20 | }
21 | }
22 | class BottomWaveClipper extends CustomClipper {
23 | @override
24 | Path getClip(Size size) {
25 | var path = new Path();
26 | path.lineTo(0.0, size.height - 20);
27 |
28 | var firstControlPoint = Offset(size.width / 4, size.height);
29 | var firstEndPoint = Offset(size.width / 2.25, size.height - 30.0);
30 | path.quadraticBezierTo(firstControlPoint.dx, firstControlPoint.dy,
31 | firstEndPoint.dx, firstEndPoint.dy);
32 |
33 | var secondControlPoint = Offset(size.width - (size.width / 3.25), size.height - 65);
34 | var secondEndPoint = Offset(size.width , size.height - 30);
35 | path.quadraticBezierTo(secondControlPoint.dx, secondControlPoint.dy,
36 | secondEndPoint.dx, secondEndPoint.dy);
37 |
38 | var thirdControlPoint =
39 | Offset(size.width - (size.width / 5), size.height -size.height/3.25);
40 | var thirdEndPoint = Offset(size.width - 50, size.height/2);
41 | path.quadraticBezierTo(thirdControlPoint.dx, thirdControlPoint.dy,
42 | thirdEndPoint.dx, thirdEndPoint.dy);
43 |
44 | // path.lineTo(size.width, 0);
45 |
46 | var fourthControlPoint = Offset(size.width ,size.height /4 );
47 | var fourthEndPoint = Offset(size.width - 40,0);
48 | path.quadraticBezierTo(fourthControlPoint.dx, fourthControlPoint.dy,
49 | fourthEndPoint.dx, fourthEndPoint.dy);
50 |
51 | path.lineTo(size.width ,0);
52 | // path.lineTo(size.width, 0.0);
53 | path.close();
54 |
55 | return path;
56 | }
57 |
58 | @override
59 | bool shouldReclip(CustomClipper oldClipper) => true;
60 | }
--------------------------------------------------------------------------------
/lib/page/settings/accountSettings/contentPrefrences/contentPreference.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/model/user.dart';
4 | import 'package:flutter_twitter_clone/page/settings/widgets/headerWidget.dart';
5 | import 'package:flutter_twitter_clone/page/settings/widgets/settingsAppbar.dart';
6 | import 'package:flutter_twitter_clone/page/settings/widgets/settingsRowWidget.dart';
7 | import 'package:flutter_twitter_clone/state/authState.dart';
8 | import 'package:flutter_twitter_clone/widgets/customAppBar.dart';
9 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
10 | import 'package:flutter_twitter_clone/widgets/newWidget/customUrlText.dart';
11 | import 'package:provider/provider.dart';
12 |
13 | class ContentPrefrencePage extends StatelessWidget {
14 | const ContentPrefrencePage({Key key}) : super(key: key);
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | var user = Provider.of(context).userModel ?? UserModel();
19 | return Scaffold(
20 | backgroundColor: TwitterColor.white,
21 | appBar: SettingsAppBar(
22 | title: 'Content preferences',
23 | subtitle: user.userName,
24 | ),
25 | body: ListView(
26 | physics: BouncingScrollPhysics(),
27 | children: [
28 | HeaderWidget('Explore'),
29 | SettingRowWidget(
30 | "Trends",
31 | navigateTo: 'TrendsPage',
32 | ),
33 | Divider(height: 0),
34 | SettingRowWidget(
35 | "Search settings",
36 | navigateTo: null,
37 | ),
38 | HeaderWidget(
39 | 'Languages',
40 | secondHeader: true,
41 | ),
42 | SettingRowWidget(
43 | "Recommendations",
44 | vPadding: 15,
45 | subtitle:
46 | "Select which language you want recommended Tweets, people, and trends to include",
47 | ),
48 | HeaderWidget(
49 | 'Safety',
50 | secondHeader: true,
51 | ),
52 | SettingRowWidget("Blocked accounts"),
53 | SettingRowWidget("Muted accounts"),
54 | ],
55 | ),
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/page/Auth/widget/googleLoginButton.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/utility.dart';
3 | import 'package:flutter_twitter_clone/state/authState.dart';
4 | import 'package:flutter_twitter_clone/widgets/newWidget/customLoader.dart';
5 | import 'package:flutter_twitter_clone/widgets/newWidget/rippleButton.dart';
6 | import 'package:flutter_twitter_clone/widgets/newWidget/title_text.dart';
7 | import 'package:provider/provider.dart';
8 |
9 | class GoogleLoginButton extends StatelessWidget {
10 | const GoogleLoginButton({Key key, @required this.loader, this.loginCallback});
11 | final CustomLoader loader;
12 | final Function loginCallback;
13 | void _googleLogin(context) {
14 | var state = Provider.of(context, listen: false);
15 | loader.showLoader(context);
16 | state.handleGoogleSignIn().then((status) {
17 | // print(status)
18 | if (state.user != null) {
19 | loader.hideLoader();
20 | Navigator.pop(context);
21 | loginCallback();
22 | } else {
23 | loader.hideLoader();
24 | cprint('Unable to login', errorIn: '_googleLoginButton');
25 | }
26 | });
27 | }
28 |
29 | @override
30 | Widget build(BuildContext context) {
31 | return RippleButton(
32 | onPressed: (){
33 | _googleLogin(context);
34 | },
35 | borderRadius: BorderRadius.circular(10),
36 | child: Container(
37 | padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
38 | decoration: BoxDecoration(
39 | color: Colors.white,
40 | borderRadius: BorderRadius.circular(10),
41 | boxShadow: [
42 | BoxShadow(
43 | color: Color(0xffeeeeee),
44 | blurRadius: 15,
45 | offset: Offset(5, 5),
46 | ),
47 | ],
48 | ),
49 | child: Wrap(
50 | children: [
51 | Image.asset(
52 | 'assets/images/google_logo.png',
53 | height: 20,
54 | width: 20,
55 | ),
56 | SizedBox(width: 10),
57 | TitleText(
58 | 'Continue with Google',
59 | color: Colors.black54,
60 | ),
61 | ],
62 | ),
63 | ),
64 | );
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/lib/page/settings/accountSettings/about/aboutTwitter.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/helper/utility.dart';
4 | import 'package:flutter_twitter_clone/page/settings/widgets/headerWidget.dart';
5 | import 'package:flutter_twitter_clone/page/settings/widgets/settingsRowWidget.dart';
6 | import 'package:flutter_twitter_clone/widgets/customAppBar.dart';
7 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
8 | import 'package:flutter_twitter_clone/widgets/newWidget/title_text.dart';
9 |
10 | class AboutPage extends StatelessWidget {
11 | const AboutPage({Key key}) : super(key: key);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return Scaffold(
16 | backgroundColor: TwitterColor.white,
17 | appBar: CustomAppBar(
18 | isBackButton: true,
19 | title: customTitleText(
20 | 'About Fwitter',
21 | ),
22 | ),
23 | body: ListView(
24 | physics: BouncingScrollPhysics(),
25 | children: [
26 | HeaderWidget(
27 | 'Help',
28 | secondHeader: true,
29 | ),
30 | SettingRowWidget(
31 | "Help Centre",
32 | vPadding: 15,
33 | showDivider: false,
34 | onPressed: (){
35 | launchURL("https://github.com/TheAlphamerc/flutter_twitter_clone/issues");
36 | },
37 | ),
38 | HeaderWidget('Legal'),
39 | SettingRowWidget(
40 | "Terms of Service",
41 | showDivider: true,
42 | ),
43 | SettingRowWidget(
44 | "Privacy policy",
45 | showDivider: true,
46 | ),
47 | SettingRowWidget(
48 | "Cookie use",
49 | showDivider: true,
50 | ),
51 | SettingRowWidget(
52 | "Legal notices",
53 | showDivider: true,
54 | onPressed: () async {
55 | showLicensePage(
56 | context: context,
57 | applicationName: 'Fwitter',
58 | applicationVersion: '1.0.0',
59 | useRootNavigator: true,
60 | );
61 | },
62 | )
63 | ],
64 | ),
65 | );
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/lib/page/profile/profileImageView.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/helper/utility.dart';
4 | import 'package:flutter_twitter_clone/page/profile/profilePage.dart';
5 | import 'package:flutter_twitter_clone/state/authState.dart';
6 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
7 | import 'package:provider/provider.dart';
8 |
9 | class ProfileImageView extends StatelessWidget {
10 | const ProfileImageView({Key key}) : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | const List choices = const [
15 | const Choice(title: 'Share image link', icon: Icons.share),
16 | const Choice(title: 'Open in browser', icon: Icons.open_in_browser),
17 | const Choice(title: 'Save', icon: Icons.save),
18 | ];
19 | var authstate = Provider.of(context, listen: false);
20 | return Scaffold(
21 | backgroundColor: TwitterColor.white,
22 | appBar: AppBar(
23 | actions: [
24 | PopupMenuButton(
25 | onSelected: (d) {
26 | switch (d.title) {
27 | case "Share image link": share(authstate.profileUserModel.profilePic); break;
28 | case "Open in browser": launchURL(authstate.profileUserModel.profilePic); break;
29 | case "Save": break;
30 | }
31 |
32 | },
33 | itemBuilder: (BuildContext context) {
34 | return choices.map((Choice choice) {
35 | return PopupMenuItem(
36 | value: choice,
37 | child: Text(choice.title),
38 | );
39 | }).toList();
40 | },
41 | ),
42 | ],
43 | ),
44 | body: Center(
45 | child: Container(
46 | alignment: Alignment.center,
47 | width: fullWidth(context),
48 | // height: fullWidth(context),
49 | decoration: BoxDecoration(
50 | image: DecorationImage(
51 | image: customAdvanceNetworkImage(
52 | authstate.profileUserModel.profilePic),
53 | fit: BoxFit.contain,
54 | ),
55 | ),
56 | ),
57 | ),
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .packages
28 | .pub-cache/
29 | .pub/
30 | /build/
31 |
32 | # Android related
33 | **/android/**/gradle-wrapper.jar
34 | **/android/.gradle
35 | **/android/captures/
36 | **/android/gradlew
37 | **/android/gradlew.bat
38 | **/android/local.properties
39 | **/android/**/GeneratedPluginRegistrant.java
40 | **/android/app/google-services.json
41 | **/android/app/key.jks
42 |
43 | # iOS/XCode related
44 | **/ios/**/*.mode1v3
45 | **/ios/**/*.mode2v3
46 | **/ios/**/*.moved-aside
47 | **/ios/**/*.pbxuser
48 | **/ios/**/*.perspectivev3
49 | **/ios/**/*sync/
50 | **/ios/**/.sconsign.dblite
51 | **/ios/**/.tags*
52 | **/ios/**/.vagrant/
53 | **/ios/**/DerivedData/
54 | **/ios/**/Icon?
55 | **/ios/**/Pods/
56 | **/ios/**/.symlinks/
57 | **/ios/**/profile
58 | **/ios/**/xcuserdata
59 | **/ios/.generated/
60 | **/ios/Flutter/App.framework
61 | **/ios/Flutter/Flutter.framework
62 | **/ios/Flutter/Generated.xcconfig
63 | **/ios/Flutter/app.flx
64 | **/ios/Flutter/app.zip
65 | **/ios/Flutter/flutter_assets/
66 | **/ios/Flutter/flutter_export_environment.sh
67 | **/ios/ServiceDefinitions.json
68 | **/ios/Runner/GeneratedPluginRegistrant.*
69 | **/ios/Runner/GoogleService-Info.plist
70 | /Users/ashwindas/Desktop/Workspace/Git Projects/flutter_twitter_clone/ios/Runner/GoogleService-Info.plist
71 | GoogleService-Info.plist
72 |
73 | # Exceptions to above rules.
74 | !**/ios/**/default.mode1v3
75 | !**/ios/**/default.mode2v3
76 | !**/ios/**/default.pbxuser
77 | !**/ios/**/default.perspectivev3
78 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
79 | .flutter-plugins-dependencies
80 | android/app/google-services.json
81 | google-services.json
82 |
83 | android/.settings/org.eclipse.buildship.core.prefs
84 | android/app/.classpath
85 | android/.project
86 | android/app/.project
87 | android/app/.settings/org.eclipse.buildship.core.prefs
88 | android/app/.settings/org.eclipse.jdt.core.prefs
89 |
--------------------------------------------------------------------------------
/lib/page/settings/widgets/settingsRowWidget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/widgets/newWidget/customUrlText.dart';
4 |
5 | class SettingRowWidget extends StatelessWidget {
6 | const SettingRowWidget(
7 | this.title, {
8 | Key key,
9 | this.navigateTo,
10 | this.subtitle,
11 | this.textColor = Colors.black,
12 | this.onPressed,
13 | this.vPadding = 0,
14 | this.showDivider = true,
15 | this.visibleSwitch = false,
16 | this.showCheckBox = false,
17 | }) : super(key: key);
18 | final bool visibleSwitch, showDivider, showCheckBox;
19 | final String navigateTo;
20 | final String subtitle, title;
21 | final Color textColor;
22 | final Function onPressed;
23 | final double vPadding;
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | return Column(
28 | children: [
29 | ListTile(
30 | contentPadding:
31 | EdgeInsets.symmetric(vertical: vPadding, horizontal: 18),
32 | onTap: () {
33 | if (onPressed != null) {
34 | onPressed();
35 | return;
36 | }
37 | if (navigateTo == null) {
38 | return;
39 | }
40 | Navigator.pushNamed(context, '/$navigateTo');
41 | },
42 | title: title == null
43 | ? null
44 | : UrlText(
45 | text: title ?? '',
46 | style: TextStyle(fontSize: 16, color: textColor),
47 | ),
48 | subtitle: subtitle == null
49 | ? null
50 | : UrlText(
51 | text: subtitle,
52 | style: TextStyle(
53 | color: TwitterColor.paleSky, fontWeight: FontWeight.w400),
54 | ),
55 | trailing: showCheckBox
56 | ? !showCheckBox
57 | ? SizedBox()
58 | : Checkbox(value: true, onChanged: (val) {})
59 | : !visibleSwitch
60 | ? null
61 | : Switch(
62 | onChanged: (val) {},
63 | value: false,
64 | ),
65 | ),
66 | !showDivider ? SizedBox() : Divider(height: 0)
67 | ],
68 | );
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/page/settings/accountSettings/notifications/notificationPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/model/user.dart';
4 | import 'package:flutter_twitter_clone/page/settings/widgets/headerWidget.dart';
5 | import 'package:flutter_twitter_clone/page/settings/widgets/settingsAppbar.dart';
6 | import 'package:flutter_twitter_clone/page/settings/widgets/settingsRowWidget.dart';
7 | import 'package:flutter_twitter_clone/state/authState.dart';
8 | import 'package:flutter_twitter_clone/widgets/newWidget/customUrlText.dart';
9 | import 'package:provider/provider.dart';
10 |
11 | class NotificationPage extends StatelessWidget {
12 | const NotificationPage({Key key}) : super(key: key);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | var user = Provider.of(context).userModel ?? UserModel();
17 | return Scaffold(
18 | backgroundColor: TwitterColor.white,
19 | appBar: SettingsAppBar(
20 | title: 'Notifications',
21 | subtitle: user.userName,
22 | ),
23 | body: ListView(
24 | children: [
25 | HeaderWidget('Filters'),
26 | SettingRowWidget(
27 | "Quality filter",
28 | showCheckBox: true,
29 | subtitle:
30 | 'Filter lower-quality from your notifications. This won\'t filter out notifications from people you follow or account you\'ve inteacted with recently.',
31 | // navigateTo: 'AccountSettingsPage',
32 | ),
33 | Divider(height: 0),
34 | SettingRowWidget("Advanced filter"),
35 | SettingRowWidget("Muted word"),
36 | HeaderWidget(
37 | 'Preferences',
38 | secondHeader: true,
39 | ),
40 | SettingRowWidget(
41 | "Unread notification count badge",
42 | showCheckBox: true,
43 | subtitle:
44 | 'Display a badge with the number of notifications waiting for you inside the Fwitter app.',
45 | ),
46 | SettingRowWidget("Push notifications"),
47 | SettingRowWidget("SMS notifications"),
48 | SettingRowWidget(
49 | "Email notifications",
50 | subtitle: 'Control when how often Fwitter sends emails to you.',
51 | ),
52 | ],
53 | ),
54 | );
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/lib/widgets/tweet/widgets/tweetImage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/enum.dart';
3 | import 'package:flutter_twitter_clone/model/feedModel.dart';
4 | import 'package:flutter_twitter_clone/state/feedState.dart';
5 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
6 | import 'package:provider/provider.dart';
7 |
8 | class TweetImage extends StatelessWidget {
9 | const TweetImage(
10 | {Key key, this.model, this.type, this.isRetweetImage = false})
11 | : super(key: key);
12 |
13 | final FeedModel model;
14 | final TweetType type;
15 | final bool isRetweetImage;
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return AnimatedContainer(
20 | duration: Duration(milliseconds: 500),
21 | alignment: Alignment.centerRight,
22 | child: model.imagePath == null
23 | ? SizedBox.shrink()
24 | : Padding(
25 | padding: EdgeInsets.only(
26 | top: 8,
27 | ),
28 | child: InkWell(
29 | borderRadius: BorderRadius.all(
30 | Radius.circular(isRetweetImage ? 0 : 20),
31 | ),
32 | onTap: () {
33 | if(type == TweetType.ParentTweet){
34 | return;
35 | }
36 | var state = Provider.of(context, listen: false);
37 | // state.getpostDetailFromDatabase(model.key, model: model);
38 | state.setTweetToReply = model;
39 | Navigator.pushNamed(context, '/ImageViewPge');
40 | },
41 | child: ClipRRect(
42 | borderRadius: BorderRadius.all(
43 | Radius.circular(isRetweetImage ? 0 : 20),
44 | ),
45 | child: Container(
46 | width: fullWidth(context) *
47 | (type == TweetType.Detail ? .95 : .8) -
48 | 8,
49 | decoration: BoxDecoration(
50 | color: Theme.of(context).backgroundColor,
51 | ),
52 | child: AspectRatio(
53 | aspectRatio: 4 / 3,
54 | child: customNetworkImage(model.imagePath,
55 | fit: BoxFit.cover),
56 | ),
57 | ),
58 | ),
59 | ),
60 | ),
61 | );
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | flutter_twitter_clone
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 | NSPhotoLibraryUsageDescription
45 | This app requires access to the photo library.
46 | NSMicrophoneUsageDescription
47 | This app does not require access to the microphone.
48 | NSCameraUsageDescription
49 | This app requires access to the camera.
50 | CFBundleURLTypes
51 |
52 |
53 | CFBundleTypeRole
54 | Editor
55 | CFBundleURLSchemes
56 |
57 |
58 |
59 | com.googleusercontent.apps.473051771699-52pt7hu6fqqk7q5iumj6ovfmfqemkeb1
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/lib/page/settings/settingsAndPrivacyPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/model/user.dart';
4 | import 'package:flutter_twitter_clone/page/settings/widgets/headerWidget.dart';
5 | import 'package:flutter_twitter_clone/state/authState.dart';
6 | import 'package:flutter_twitter_clone/widgets/customAppBar.dart';
7 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
8 | import 'package:flutter_twitter_clone/widgets/newWidget/customUrlText.dart';
9 | import 'package:provider/provider.dart';
10 | import 'widgets/settingsRowWidget.dart';
11 |
12 | class SettingsAndPrivacyPage extends StatelessWidget {
13 | const SettingsAndPrivacyPage({Key key}) : super(key: key);
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | var user = Provider.of(context).userModel ?? UserModel();
18 | return Scaffold(
19 | backgroundColor: TwitterColor.white,
20 | appBar: CustomAppBar(
21 | isBackButton: true,
22 | title: customTitleText(
23 | 'Settings and privacy',
24 | ),
25 | ),
26 | body: ListView(
27 | children: [
28 | HeaderWidget(user.userName),
29 | SettingRowWidget(
30 | "Account",
31 | navigateTo: 'AccountSettingsPage',
32 | ),
33 | Divider(height: 0),
34 | SettingRowWidget("Privacy and Policy",
35 | navigateTo: 'PrivacyAndSaftyPage'),
36 | SettingRowWidget("Notification", navigateTo: 'NotificationPage'),
37 | SettingRowWidget("Content prefrences",
38 | navigateTo: 'ContentPrefrencePage'),
39 | HeaderWidget(
40 | 'General',
41 | secondHeader: true,
42 | ),
43 | SettingRowWidget("Display and Sound",
44 | navigateTo: 'DisplayAndSoundPage'),
45 | SettingRowWidget("Data usage", navigateTo: 'DataUsagePage'),
46 | SettingRowWidget("Accessibility", navigateTo: 'AccessibilityPage'),
47 | SettingRowWidget("Proxy", navigateTo: "ProxyPage"),
48 | SettingRowWidget(
49 | "About Fwitter",
50 | navigateTo: "AboutPage",
51 | ),
52 | SettingRowWidget(
53 | null,
54 | showDivider: false,
55 | vPadding: 10,
56 | subtitle:
57 | 'These settings affect all of your Fwitter accounts on this devce.',
58 | )
59 | ],
60 | ),
61 | );
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/lib/page/settings/accountSettings/accountSettingsPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/model/user.dart';
4 | import 'package:flutter_twitter_clone/page/settings/widgets/headerWidget.dart';
5 | import 'package:flutter_twitter_clone/page/settings/widgets/settingsAppbar.dart';
6 | import 'package:flutter_twitter_clone/page/settings/widgets/settingsRowWidget.dart';
7 | import 'package:flutter_twitter_clone/state/authState.dart';
8 | import 'package:flutter_twitter_clone/widgets/customAppBar.dart';
9 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
10 | import 'package:flutter_twitter_clone/widgets/newWidget/customUrlText.dart';
11 | import 'package:provider/provider.dart';
12 |
13 | class AccountSettingsPage extends StatelessWidget {
14 | const AccountSettingsPage({Key key}) : super(key: key);
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | var user = Provider.of(context).userModel ?? UserModel();
19 | return Scaffold(
20 | backgroundColor: TwitterColor.white,
21 | appBar: SettingsAppBar(
22 | title: 'Account',
23 | subtitle: user?.userName,
24 | ),
25 | body: ListView(
26 | children: [
27 | HeaderWidget('Login and security'),
28 | SettingRowWidget(
29 | "Username",
30 | subtitle: user?.userName,
31 | // navigateTo: 'AccountSettingsPage',
32 | ),
33 | Divider(height: 0),
34 | SettingRowWidget(
35 | "Phone",
36 | subtitle: user?.contact,
37 | ),
38 | SettingRowWidget(
39 | "Email address",
40 | subtitle: user?.email,
41 | navigateTo: 'VerifyEmailPage',
42 | ),
43 | SettingRowWidget("Password"),
44 | SettingRowWidget("Security"),
45 | HeaderWidget(
46 | 'Data and Permission',
47 | secondHeader: true,
48 | ),
49 | SettingRowWidget("Country"),
50 | SettingRowWidget("Your Fwitter data"),
51 | SettingRowWidget("Apps and sessions"),
52 | SettingRowWidget(
53 | "Log out",
54 | textColor: TwitterColor.ceriseRed,
55 | onPressed: () {
56 | Navigator.popUntil(context, ModalRoute.withName('/'));
57 | final state = Provider.of(context);
58 | state.logoutCallback();
59 | },
60 | ),
61 | ],
62 | ),
63 | );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/lib/page/common/usersListPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/model/user.dart';
4 | import 'package:flutter_twitter_clone/page/common/widget/userListWidget.dart';
5 | import 'package:flutter_twitter_clone/state/searchState.dart';
6 | import 'package:flutter_twitter_clone/widgets/customAppBar.dart';
7 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
8 | import 'package:flutter_twitter_clone/widgets/newWidget/emptyList.dart';
9 | import 'package:provider/provider.dart';
10 |
11 | class UsersListPage extends StatelessWidget {
12 | UsersListPage({
13 | Key key,
14 | this.pageTitle = "",
15 | this.appBarIcon,
16 | this.emptyScreenText,
17 | this.emptyScreenSubTileText,
18 | this.userIdsList,
19 | }) : super(key: key);
20 |
21 | final String pageTitle;
22 | final String emptyScreenText;
23 | final String emptyScreenSubTileText;
24 | final int appBarIcon;
25 | final List userIdsList;
26 |
27 | @override
28 | Widget build(BuildContext context) {
29 | List userList;
30 | return Scaffold(
31 | backgroundColor: TwitterColor.mystic,
32 | appBar: CustomAppBar(
33 | isBackButton: true,
34 | title: customTitleText(pageTitle),
35 | icon: appBarIcon),
36 | body: Consumer(
37 | builder: (context, state, child) {
38 | if (userIdsList != null) {
39 | /// If userIdsList Is not null then
40 | /// Fetch user corresponding to userId from search user page
41 | /// Search user page contains all user's profile data
42 | userList = state.getuserDetail(userIdsList);
43 | }
44 | return !(userList != null && userList.isNotEmpty)
45 |
46 | /// If user list is empty then display empty list message
47 | ? Container(
48 | width: fullWidth(context),
49 | padding: EdgeInsets.only(top: 0, left: 30, right: 30),
50 | child: NotifyText(
51 | title: emptyScreenText,
52 | subTitle: emptyScreenSubTileText,
53 | ),
54 | )
55 |
56 | /// If user list is not empty then display user list
57 | : UserListWidget(
58 | userslist: userList,
59 | emptyScreenText: emptyScreenText,
60 | emptyScreenSubTileText: emptyScreenSubTileText,
61 | );
62 | },
63 | ),
64 | );
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
9 |
10 |
14 |
21 |
25 |
29 |
34 |
38 |
39 |
40 |
41 |
42 |
43 |
45 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/lib/page/common/splash.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/cupertino.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_twitter_clone/helper/enum.dart';
6 | import 'package:flutter_twitter_clone/helper/theme.dart';
7 | import 'package:flutter_twitter_clone/page/Auth/selectAuthMethod.dart';
8 | import 'package:flutter_twitter_clone/page/homePage.dart';
9 | import 'package:flutter_twitter_clone/state/authState.dart';
10 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
11 | import 'package:provider/provider.dart';
12 |
13 | class SplashPage extends StatefulWidget {
14 | SplashPage({Key key}) : super(key: key);
15 |
16 | @override
17 | _SplashPageState createState() => _SplashPageState();
18 | }
19 |
20 | class _SplashPageState extends State {
21 | @override
22 | void initState() {
23 | WidgetsBinding.instance.addPostFrameCallback((_) {
24 | timer();
25 | });
26 | super.initState();
27 | }
28 |
29 | void timer() async {
30 | Future.delayed(Duration(seconds: 1)).then((_) {
31 | var state = Provider.of(context, listen: false);
32 | // state.authStatus = AuthStatus.NOT_DETERMINED;
33 | state.getCurrentUser();
34 | });
35 | }
36 |
37 | Widget _body() {
38 | var height = 150.0;
39 | return Container(
40 | height: fullHeight(context),
41 | width: fullWidth(context),
42 | child: Container(
43 | height: height,
44 | width: height,
45 | alignment: Alignment.center,
46 | child: Container(
47 | padding: EdgeInsets.all(50),
48 | decoration: BoxDecoration(
49 | color: Colors.white,
50 | borderRadius: BorderRadius.all(
51 | Radius.circular(10),
52 | ),
53 | ),
54 | child: Stack(
55 | alignment: Alignment.center,
56 | children: [
57 | Platform.isIOS
58 | ? CupertinoActivityIndicator(
59 | radius: 35,
60 | )
61 | : CircularProgressIndicator(
62 | strokeWidth: 2,
63 | ),
64 | Image.asset(
65 | 'assets/images/icon-480.png',
66 | height: 30,
67 | width: 30,
68 | )
69 | ],
70 | ),
71 | ),
72 | ),
73 | );
74 | }
75 |
76 | @override
77 | Widget build(BuildContext context) {
78 | var state = Provider.of(context);
79 | return Scaffold(
80 | backgroundColor: TwitterColor.white,
81 | body: state.authStatus == AuthStatus.NOT_DETERMINED
82 | ? _body()
83 | : state.authStatus == AuthStatus.NOT_LOGGED_IN
84 | ? WelcomePage()
85 | : HomePage(),
86 | );
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/lib/widgets/newWidget/customUrlText.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/gestures.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_twitter_clone/helper/utility.dart';
4 | class UrlText extends StatelessWidget {
5 | final String text;
6 | final TextStyle style;
7 | final TextStyle urlStyle;
8 | final Function(String) onHashTagPressed;
9 |
10 | UrlText({this.text, this.style, this.urlStyle, this.onHashTagPressed});
11 |
12 | List getTextSpans() {
13 | List widgets = List();
14 | RegExp reg = RegExp(
15 | r"([#])\w+| [@]\w+|(https?|ftp|file|#)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]*");
16 | Iterable _matches = reg.allMatches(text);
17 | List<_ResultMatch> resultMatches = List<_ResultMatch>();
18 | int start = 0;
19 | for (Match match in _matches) {
20 | if (match.group(0).isNotEmpty) {
21 | if (start != match.start) {
22 | _ResultMatch result1 = _ResultMatch();
23 | result1.isUrl = false;
24 | result1.text = text.substring(start, match.start);
25 | resultMatches.add(result1);
26 | }
27 |
28 | _ResultMatch result2 = _ResultMatch();
29 | result2.isUrl = true;
30 | result2.text = match.group(0);
31 | resultMatches.add(result2);
32 | start = match.end;
33 | }
34 | }
35 | if (start < text.length) {
36 | _ResultMatch result1 = _ResultMatch();
37 | result1.isUrl = false;
38 | result1.text = text.substring(start);
39 | resultMatches.add(result1);
40 | }
41 | for (var result in resultMatches) {
42 | if (result.isUrl) {
43 | widgets.add(_LinkTextSpan(
44 | onHashTagPressed: onHashTagPressed,
45 | text: result.text,
46 | style:
47 | urlStyle != null ? urlStyle : TextStyle(color: Colors.blue)));
48 | } else {
49 | widgets.add(TextSpan(
50 | text: result.text,
51 | style: style != null ? style : TextStyle(color: Colors.black)));
52 | }
53 | }
54 | return widgets;
55 | }
56 |
57 | @override
58 | Widget build(BuildContext context) {
59 | return RichText(
60 | text: TextSpan(children: getTextSpans()),
61 | );
62 | }
63 | }
64 |
65 | class _LinkTextSpan extends TextSpan {
66 | final Function(String) onHashTagPressed;
67 | _LinkTextSpan({TextStyle style, String text, this.onHashTagPressed})
68 | : super(
69 | style: style,
70 | text: text,
71 | recognizer: TapGestureRecognizer()
72 | ..onTap = () {
73 | if(onHashTagPressed != null && (text.substring(0,1).contains("#") || text.substring(0,1).contains("#"))){
74 | onHashTagPressed(text);
75 | }
76 | else{
77 | launchURL(text);
78 | }
79 | });
80 | }
81 |
82 | class _ResultMatch {
83 | bool isUrl;
84 | String text;
85 | }
--------------------------------------------------------------------------------
/lib/widgets/newWidget/customProgressbar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | /// A progress bar with rounded corners and custom colors.
4 | class CustomProgressbar extends StatefulWidget {
5 | const CustomProgressbar(
6 | {@required this.progress,
7 | Key key,
8 | this.color,
9 | this.background = const Color.fromRGBO(0, 0, 0, 0.06),
10 | this.height = 7,
11 | this.borderRadius,
12 | this.innerPadding = const EdgeInsets.all(0)})
13 | : super(key: key);
14 |
15 | final double progress;
16 | final Color background;
17 | final Color color;
18 | final double height;
19 | final EdgeInsets innerPadding;
20 | final BorderRadius borderRadius;
21 |
22 | @override
23 | _CustomProgressbarState createState() => _CustomProgressbarState();
24 | }
25 |
26 | class _CustomProgressbarState extends State
27 | with SingleTickerProviderStateMixin {
28 | AnimationController _animationController;
29 | Animation _progressTween;
30 |
31 | @override
32 | void initState() {
33 | _animationController = AnimationController(
34 | vsync: this, duration: const Duration(milliseconds: 500));
35 | _progressTween = Tween(begin: widget.progress, end: widget.progress)
36 | .animate(_animationController);
37 | super.initState();
38 | }
39 |
40 | @override
41 | void dispose() {
42 | _animationController.dispose();
43 | super.dispose();
44 | }
45 |
46 | @override
47 | void didUpdateWidget(CustomProgressbar oldWidget) {
48 | setState(() {
49 | _progressTween =
50 | Tween(begin: _progressTween.value, end: widget.progress)
51 | .animate(_animationController);
52 | _animationController.reset();
53 | _animationController.forward();
54 | });
55 | super.didUpdateWidget(oldWidget);
56 | }
57 |
58 | @override
59 | Widget build(BuildContext context) {
60 | return Container(
61 | height: widget.height,
62 | child: Stack(
63 | children: [
64 | ConstrainedBox(
65 | constraints: const BoxConstraints(minWidth: double.infinity),
66 | child: Container(
67 | decoration: BoxDecoration(
68 | color: widget.background, borderRadius: widget.borderRadius),
69 | ),
70 | ),
71 | AnimatedBuilder(
72 | animation: _animationController,
73 | builder: (BuildContext context,Widget child) => FractionallySizedBox(
74 | widthFactor: _progressTween.value,
75 | child: Padding(
76 | padding: widget.innerPadding,
77 | child: child
78 | ),
79 | ),
80 | child: Container(
81 | height: widget.height,
82 | decoration: BoxDecoration(
83 | color: widget.color,
84 | borderRadius: widget.borderRadius),
85 | ),
86 | )
87 | ],
88 | ),
89 | );
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/lib/widgets/newWidget/customLoader.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/cupertino.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
6 |
7 | class CustomLoader {
8 | static CustomLoader _customLoader;
9 |
10 | CustomLoader._createObject();
11 |
12 | factory CustomLoader() {
13 | if (_customLoader != null) {
14 | return _customLoader;
15 | } else {
16 | _customLoader = CustomLoader._createObject();
17 | return _customLoader;
18 | }
19 | }
20 |
21 | //static OverlayEntry _overlayEntry;
22 | OverlayState _overlayState; //= new OverlayState();
23 | OverlayEntry _overlayEntry;
24 |
25 | _buildLoader() {
26 | _overlayEntry = OverlayEntry(
27 | builder: (context) {
28 | return Container(
29 | height: fullHeight(context),
30 | width: fullWidth(context),
31 | child: buildLoader(context));
32 | },
33 | );
34 | }
35 |
36 | showLoader(context) {
37 | _overlayState = Overlay.of(context);
38 | _buildLoader();
39 | _overlayState.insert(_overlayEntry);
40 | }
41 |
42 | hideLoader() {
43 | try {
44 | _overlayEntry?.remove();
45 | _overlayEntry = null;
46 | } catch (e) {
47 | print("Exception:: $e");
48 | }
49 | }
50 |
51 | buildLoader(BuildContext context, {Color backgroundColor}) {
52 | if(backgroundColor == null){
53 | backgroundColor = const Color(0xffa8a8a8).withOpacity(.5);
54 | }
55 | var height = 150.0;
56 | return CustomScreenLoader(
57 | height: height,
58 | width: height,
59 | backgroundColor: backgroundColor,
60 | );
61 | }
62 | }
63 |
64 | class CustomScreenLoader extends StatelessWidget {
65 | final Color backgroundColor;
66 | final double height;
67 | final double width;
68 | const CustomScreenLoader({Key key, this.backgroundColor =const Color(0xfff8f8f8), this.height = 30, this.width = 30}) : super(key: key);
69 |
70 | @override
71 | Widget build(BuildContext context) {
72 | return Container(
73 | color: backgroundColor,
74 | child: Container(
75 | height: height,
76 | width: height,
77 | alignment: Alignment.center,
78 | child: Container(
79 | padding: EdgeInsets.all(50),
80 | decoration: BoxDecoration(
81 | color: Colors.white,
82 | borderRadius: BorderRadius.all(Radius.circular(10))),
83 | child: Stack(
84 | alignment: Alignment.center,
85 | children: [
86 | Platform.isIOS
87 | ? CupertinoActivityIndicator(radius: 35,)
88 | : CircularProgressIndicator(
89 | strokeWidth: 2,
90 | ),
91 | Image.asset(
92 | 'assets/images/icon-480.png',
93 | height: 30,
94 | width: 30,
95 | )
96 | ],
97 | ),
98 | ),
99 | ),
100 | );
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/lib/widgets/bottomMenuBar/tabItem.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '../customWidgets.dart';
4 |
5 | const double ICON_OFF = -3;
6 | const double ICON_ON = 0;
7 | const double TEXT_OFF = 5;
8 | const double TEXT_ON = 1;
9 | const double ALPHA_OFF = 0;
10 | const double ALPHA_ON = 1;
11 | const int ANIM_DURATION = 300;
12 |
13 | class TabItem extends StatelessWidget {
14 | TabItem(
15 | {@required this.uniqueKey,
16 | @required this.selected,
17 | @required this.iconData,
18 | @required this.title,
19 | @required this.callbackFunction,
20 | @required this.textColor,
21 | @required this.iconColor,
22 | this.isCustomIcon,
23 | this.customIconCode});
24 |
25 | final UniqueKey uniqueKey;
26 | final String title;
27 | final IconData iconData;
28 | final bool selected;
29 | final Function(UniqueKey uniqueKey) callbackFunction;
30 | final Color textColor;
31 | final Color iconColor;
32 | final bool isCustomIcon;
33 | final int customIconCode;
34 |
35 | final double iconYAlign = ICON_ON;
36 | final double textYAlign = TEXT_OFF;
37 | final double iconAlpha = ALPHA_ON;
38 |
39 | @override
40 | Widget build(BuildContext context) {
41 | return Expanded(
42 | child: Stack(
43 | fit: StackFit.expand,
44 | children: [
45 | Container(
46 | height: double.infinity,
47 | width: double.infinity,
48 | child: AnimatedAlign(
49 | duration: Duration(milliseconds: ANIM_DURATION),
50 | alignment: Alignment(0, (selected) ? TEXT_ON : TEXT_OFF),
51 | child: Padding(
52 | padding: const EdgeInsets.all(8.0),
53 | child: Text(
54 | title,
55 | overflow: TextOverflow.ellipsis,
56 | maxLines: 1,
57 | style: TextStyle(
58 | fontWeight: FontWeight.w600, color: textColor,fontSize: getDimention(context,12)),
59 | ),
60 | )),
61 | ),
62 | Container(
63 | height: double.infinity,
64 | width: double.infinity,
65 | child: AnimatedAlign(
66 | duration: Duration(milliseconds: ANIM_DURATION),
67 | curve: Curves.easeIn,
68 | alignment: Alignment(0, (selected) ? ICON_OFF : ICON_ON),
69 | child: AnimatedOpacity(
70 | duration: Duration(milliseconds: ANIM_DURATION),
71 | opacity: (selected) ? ALPHA_OFF : ALPHA_ON,
72 | child: IconButton(
73 | highlightColor: Colors.transparent,
74 | splashColor: Colors.transparent,
75 | padding: EdgeInsets.all(0),
76 | alignment: Alignment(0, 0),
77 | icon: isCustomIcon ? customIcon(context,icon:customIconCode) :
78 | Icon(iconData,color: iconColor,),
79 | onPressed: () {
80 | callbackFunction(uniqueKey);
81 | },
82 | ),
83 | ),
84 | ),
85 | )
86 | ],
87 | ),
88 | );
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/lib/page/Auth/verifyEmail.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/state/authState.dart';
4 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
5 | import 'package:flutter_twitter_clone/widgets/newWidget/emptyList.dart';
6 | import 'package:flutter_twitter_clone/widgets/newWidget/title_text.dart';
7 | import 'package:provider/provider.dart';
8 |
9 | class VerifyEmailPage extends StatefulWidget {
10 | final VoidCallback loginCallback;
11 |
12 | const VerifyEmailPage({Key key, this.loginCallback}) : super(key: key);
13 | @override
14 | State createState() => _VerifyEmailPageState();
15 | }
16 |
17 | class _VerifyEmailPageState extends State {
18 | final GlobalKey _scaffoldKey = new GlobalKey();
19 |
20 | Widget _body(BuildContext context) {
21 | var state = Provider.of(context, listen: false);
22 | return Container(
23 | height: fullHeight(context),
24 | padding: EdgeInsets.symmetric(horizontal: 10),
25 | child: Column(
26 | mainAxisAlignment: MainAxisAlignment.center,
27 | crossAxisAlignment: CrossAxisAlignment.center,
28 | children: state.user.emailVerified
29 | ? [
30 | NotifyText(
31 | title: 'Your email address is verified',
32 | subTitle:
33 | 'You have got your blue tick on your name. Cheers !!',
34 | ),
35 | ]
36 | : [
37 | NotifyText(
38 | title: 'Verify your email address',
39 | subTitle:
40 | 'Send email verification email link to ${state.user.email} to verify address',
41 | ),
42 | SizedBox(
43 | height: 30,
44 | ),
45 | _submitButton(context),
46 | ],
47 | ),
48 | );
49 | }
50 |
51 | Widget _submitButton(BuildContext context) {
52 | return Container(
53 | margin: EdgeInsets.symmetric(vertical: 15),
54 | width: MediaQuery.of(context).size.width,
55 | alignment: Alignment.center,
56 | child: Wrap(
57 | children: [
58 | MaterialButton(
59 | shape: RoundedRectangleBorder(
60 | borderRadius: BorderRadius.circular(30),
61 | ),
62 | color: Colors.blueAccent,
63 | onPressed: _submit,
64 | padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10),
65 | child: TitleText(
66 | 'Send Link',
67 | color: Colors.white,
68 | ),
69 | ),
70 | ],
71 | ),
72 | );
73 | }
74 |
75 | void _submit() {
76 | var state = Provider.of(context, listen: false);
77 | state.sendEmailVerification(_scaffoldKey);
78 | }
79 |
80 | @override
81 | Widget build(BuildContext context) {
82 | return Scaffold(
83 | key: _scaffoldKey,
84 | backgroundColor: TwitterColor.mystic,
85 | appBar: AppBar(
86 | title: customText(
87 | 'Email Verification',
88 | context: context,
89 | style: TextStyle(fontSize: 20),
90 | ),
91 | centerTitle: true,
92 | ),
93 | body: _body(context),
94 | );
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/lib/model/feedModel.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_twitter_clone/model/user.dart';
2 |
3 | class FeedModel {
4 | String key;
5 | String parentkey;
6 | String childRetwetkey;
7 | String description;
8 | String userId;
9 | int likeCount;
10 | List likeList;
11 | int commentCount;
12 | int retweetCount;
13 | String createdAt;
14 | String imagePath;
15 | List tags;
16 | List replyTweetKeyList;
17 | UserModel user;
18 | FeedModel(
19 | {this.key,
20 | this.description,
21 | this.userId,
22 | this.likeCount,
23 | this.commentCount,
24 | this.retweetCount,
25 | this.createdAt,
26 | this.imagePath,
27 | this.likeList,
28 | this.tags,
29 | this.user,
30 | this.replyTweetKeyList,
31 | this.parentkey,
32 | this.childRetwetkey});
33 | toJson() {
34 | return {
35 | "userId": userId,
36 | "description": description,
37 | "likeCount": likeCount,
38 | "commentCount": commentCount ?? 0,
39 | "retweetCount": retweetCount ?? 0,
40 | "createdAt": createdAt,
41 | "imagePath": imagePath,
42 | "likeList": likeList,
43 | "tags": tags,
44 | "replyTweetKeyList": replyTweetKeyList,
45 | "user": user == null ? null : user.toJson(),
46 | "parentkey": parentkey,
47 | "childRetwetkey": childRetwetkey
48 | };
49 | }
50 |
51 | FeedModel.fromJson(Map map) {
52 | key = map['key'];
53 | description = map['description'];
54 | userId = map['userId'];
55 | // name = map['name'];
56 | // profilePic = map['profilePic'];
57 | likeCount = map['likeCount'];
58 | commentCount = map['commentCount'];
59 | retweetCount = map["retweetCount"] ?? 0;
60 | imagePath = map['imagePath'];
61 | createdAt = map['createdAt'];
62 | imagePath = map['imagePath'];
63 | // username = map['username'];
64 | user = UserModel.fromJson(map['user']);
65 | parentkey = map['parentkey'];
66 | childRetwetkey = map['childRetwetkey'];
67 | if (map['tags'] != null) {
68 | tags = List();
69 | map['tags'].forEach((value) {
70 | tags.add(value);
71 | });
72 | }
73 | if (map["likeList"] != null) {
74 | likeList = List();
75 | final list = map['likeList'];
76 | if (list is List) {
77 | map['likeList'].forEach((value) {
78 | likeList.add(value);
79 | });
80 | likeCount = likeList.length;
81 | }
82 | } else {
83 | likeList = [];
84 | likeCount = 0;
85 | }
86 | if (map['replyTweetKeyList'] != null &&
87 | map['replyTweetKeyList'].length > 0) {
88 | map['replyTweetKeyList'].forEach((value) {
89 | replyTweetKeyList = List();
90 | map['replyTweetKeyList'].forEach((value) {
91 | replyTweetKeyList.add(value);
92 | });
93 | });
94 | commentCount = replyTweetKeyList.length;
95 | } else {
96 | replyTweetKeyList = [];
97 | commentCount = 0;
98 | }
99 | }
100 |
101 | bool get isValidTweet {
102 | bool isValid = false;
103 | if (description != null &&
104 | description.isNotEmpty &&
105 | this.user != null &&
106 | this.user.userName != null &&
107 | this.user.userName.isNotEmpty) {
108 | isValid = true;
109 | } else {
110 | print("Invalid Tweet found. Id:- $key");
111 | }
112 | return isValid;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/lib/helper/constant.dart:
--------------------------------------------------------------------------------
1 | String dummyProfilePic = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ6TaCLCqU4K0ieF27ayjl51NmitWaJAh_X0r1rLX4gMvOe0MDaYw&s';
2 | String appFont = 'HelveticaNeuea';
3 | List dummyProfilePicList = [
4 | 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ6TaCLCqU4K0ieF27ayjl51NmitWaJAh_X0r1rLX4gMvOe0MDaYw&s',
5 | 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTFDjXj1F8Ix-rRFgY_r3GerDoQwfiOMXVt-tZdv_Mcou_yIlUC&s',
6 | 'http://www.azembelani.co.za/wp-content/uploads/2016/07/20161014_58006bf6e7079-3.png',
7 | 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRzDG366qY7vXN2yng09wb517WTWqp-oua-mMsAoCadtncPybfQ&s',
8 | 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTq7BgpG1CwOveQ_gEFgOJASWjgzHAgVfyozkIXk67LzN1jnj9I&s',
9 | 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRPxjRIYT8pG0zgzKTilbko-MOv8pSnmO63M9FkOvfHoR9FvInm&s',
10 | 'https://cdn5.f-cdn.com/contestentries/753244/11441006/57c152cc68857_thumb900.jpg',
11 | 'https://cdn6.f-cdn.com/contestentries/753244/20994643/57c189b564237_thumb900.jpg'
12 | ];
13 |
14 | class AppIcon{
15 | static final int fabTweet = 0xf029;
16 | static final int messageEmpty = 0xf187;
17 | static final int messageFill = 0xf554;
18 | static final int search = 0xf058;
19 | static final int searchFill = 0xf558;
20 | static final int notification = 0xf055;
21 | static final int notificationFill = 0xf019;
22 | static final int messageFab = 0xf053;
23 | static final int home = 0xf053;
24 | static final int homeFill = 0xF553;
25 | static final int heartEmpty = 0xf148;
26 | static final int heartFill = 0xf015;
27 | static final int settings = 0xf059;
28 | static final int adTheRate = 0xf064;
29 | static final int reply = 0xf151;
30 | static final int retweet = 0xf152;
31 | static final int image = 0xf109;
32 | static final int camera = 0xf110;
33 | static final int arrowDown = 0xf196;
34 | static final int blueTick = 0xf099;
35 |
36 | static final int link = 0xf098;
37 | static final int unFollow = 0xf097;
38 | static final int mute = 0xf101;
39 | static final int viewHidden = 0xf156;
40 | static final int block = 0xe609;
41 | static final int report = 0xf038;
42 | static final int pin = 0xf088;
43 | static final int delete = 0xf154;
44 |
45 | static final int profile = 0xf056;
46 | static final int lists = 0xf094;
47 | static final int bookmark = 0xf155;
48 | static final int moments = 0xf160;
49 | static final int twitterAds = 0xf504;
50 | static final int bulb = 0xf567;
51 | static final int newMessage = 0xf035;
52 |
53 | static final int sadFace = 0xf430;
54 | static final int bulbOn = 0xf066;
55 | static final int bulbOff = 0xf567;
56 | static final int follow = 0xf175;
57 | static final int thumbpinFill = 0xf003;
58 | static final int calender = 0xf203;
59 | static final int locationPin = 0xf031;
60 | static final int edit = 0xf112;
61 |
62 | }
63 |
64 | /// Firestore collections
65 | ///
66 | /// Store `User` Model in db
67 | const String USERS_COLLECTION = "profile";
68 |
69 | /// Store `FeedModel` Model in db
70 | const String TWEET_COLLECTION = "tweet";
71 |
72 | /// Store `ChatMessage` Model in db
73 | const String MESSAGES_COLLECTION = "messages";
74 |
75 | /// Store `ChatMessage` Model in db
76 | /// `chatUsers` ate stored in `ChatMessage` on purpose
77 | const String CHAT_USER_LIST_COLLECTION = "chatUsers";
78 |
79 | /// Store `NotificationModel` Model in db
80 | const String NOTIFICATION_COLLECTION = "notification";
81 |
82 | const String FOLLOWER_COLLECTION = "followerList";
83 |
84 | const String FOLLOWING_COLLECTION = "followingList";
85 |
86 | // // Below collections is not used yet
87 | // const String TWEET_LIKE_COLLECTION = "likeList";
88 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def parse_KV_file(file, separator='=')
14 | file_abs_path = File.expand_path(file)
15 | if !File.exists? file_abs_path
16 | return [];
17 | end
18 | generated_key_values = {}
19 | skip_line_start_symbols = ["#", "/"]
20 | File.foreach(file_abs_path) do |line|
21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
22 | plugin = line.split(pattern=separator)
23 | if plugin.length == 2
24 | podname = plugin[0].strip()
25 | path = plugin[1].strip()
26 | podpath = File.expand_path("#{path}", file_abs_path)
27 | generated_key_values[podname] = podpath
28 | else
29 | puts "Invalid plugin specification: #{line}"
30 | end
31 | end
32 | generated_key_values
33 | end
34 |
35 | target 'Runner' do
36 | use_frameworks!
37 | use_modular_headers!
38 |
39 | # Flutter Pod
40 |
41 | copied_flutter_dir = File.join(__dir__, 'Flutter')
42 | copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
43 | copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
44 | unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
45 | # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
46 | # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
47 | # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
48 |
49 | generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
50 | unless File.exist?(generated_xcode_build_settings_path)
51 | raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
52 | end
53 | generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
54 | cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
55 |
56 | unless File.exist?(copied_framework_path)
57 | FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
58 | end
59 | unless File.exist?(copied_podspec_path)
60 | FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
61 | end
62 | end
63 |
64 | # Keep pod path relative so it can be checked into Podfile.lock.
65 | pod 'Flutter', :path => 'Flutter'
66 |
67 | # Plugin Pods
68 |
69 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
70 | # referring to absolute paths on developers' machines.
71 | system('rm -rf .symlinks')
72 | system('mkdir -p .symlinks/plugins')
73 | plugin_pods = parse_KV_file('../.flutter-plugins')
74 | plugin_pods.each do |name, path|
75 | symlink = File.join('.symlinks', 'plugins', name)
76 | File.symlink(path, symlink)
77 | pod name, :path => File.join(symlink, 'ios')
78 | end
79 | end
80 |
81 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
82 | install! 'cocoapods', :disable_input_output_paths => true
83 |
84 | post_install do |installer|
85 | installer.pods_project.targets.each do |target|
86 | target.build_configurations.each do |config|
87 | config.build_settings['ENABLE_BITCODE'] = 'NO'
88 | end
89 | end
90 | end
91 |
--------------------------------------------------------------------------------
/lib/widgets/bottomMenuBar/bottomMenuBar.dart:
--------------------------------------------------------------------------------
1 | // import 'package:fancy_bottom_navigation/internal/tab_item.dart';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_twitter_clone/helper/constant.dart';
5 | import 'package:flutter_twitter_clone/state/appState.dart';
6 | import 'package:flutter_twitter_clone/state/authState.dart';
7 | import 'package:flutter_twitter_clone/widgets/bottomMenuBar/tabItem.dart';
8 | import 'package:provider/provider.dart';
9 | import '../customWidgets.dart';
10 | // import 'customBottomNavigationBar.dart';
11 |
12 | class BottomMenubar extends StatefulWidget{
13 | const BottomMenubar({this.pageController});
14 | final PageController pageController;
15 | _BottomMenubarState createState() => _BottomMenubarState();
16 | }
17 | class _BottomMenubarState extends State{
18 | PageController _pageController;
19 | int _selectedIcon = 0;
20 | @override
21 | void initState() {
22 | _pageController = widget.pageController;
23 | super.initState();
24 |
25 | }
26 | Widget _iconRow(){
27 | var state = Provider.of(context,);
28 | return Container(
29 | height: 50,
30 | decoration: BoxDecoration(color: Theme.of(context).bottomAppBarColor, boxShadow: [
31 | BoxShadow(
32 | color: Colors.black12, offset: Offset(0,-.1), blurRadius: 0)
33 | ]),
34 | child: Row(
35 | mainAxisSize: MainAxisSize.max,
36 | crossAxisAlignment: CrossAxisAlignment.center,
37 | children: [
38 | _icon(null,0,icon:0 == state.pageIndex ? AppIcon.homeFill : AppIcon.home,isCustomIcon:true),
39 | _icon(null,1,icon:1 == state.pageIndex ? AppIcon.searchFill : AppIcon.search,isCustomIcon:true),
40 | _icon(null,2,icon: 2 == state.pageIndex ? AppIcon.notificationFill : AppIcon.notification,isCustomIcon:true),
41 | _icon(null,3,icon:3 == state.pageIndex ? AppIcon.messageFill :AppIcon.messageEmpty,isCustomIcon:true),
42 | ],
43 | ),
44 | );
45 | }
46 | Widget _icon(IconData iconData,int index,{bool isCustomIcon = false,int icon}){
47 | var state = Provider.of(context,);
48 | return Expanded(
49 | child: Container(
50 | height: double.infinity,
51 | width: double.infinity,
52 | child: AnimatedAlign(
53 | duration: Duration(milliseconds: ANIM_DURATION),
54 | curve: Curves.easeIn,
55 | alignment: Alignment(0, ICON_ON),
56 | child: AnimatedOpacity(
57 | duration: Duration(milliseconds: ANIM_DURATION),
58 | opacity: ALPHA_ON,
59 | child: IconButton(
60 | highlightColor: Colors.transparent,
61 | splashColor: Colors.transparent,
62 | padding: EdgeInsets.all(0),
63 | alignment: Alignment(0, 0),
64 | icon: isCustomIcon ? customIcon(context,icon:icon,size: 22, istwitterIcon: true, isEnable: index == state.pageIndex) :
65 | Icon(iconData,
66 | color:index == state.pageIndex ? Theme.of(context).primaryColor: Theme.of(context).textTheme.caption.color,
67 | ),
68 | onPressed: () {
69 | setState(() {
70 | _selectedIcon = index;
71 | state.setpageIndex = index;
72 | });
73 | },
74 | ),
75 | ),
76 | ),
77 | ),
78 | );
79 | }
80 |
81 | @override
82 | Widget build(BuildContext context) {
83 | return _iconRow();
84 | }
85 | }
--------------------------------------------------------------------------------
/lib/page/search/SearchPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/constant.dart';
3 | import 'package:flutter_twitter_clone/helper/theme.dart';
4 | import 'package:flutter_twitter_clone/helper/utility.dart';
5 | import 'package:flutter_twitter_clone/model/user.dart';
6 | import 'package:flutter_twitter_clone/state/searchState.dart';
7 | import 'package:flutter_twitter_clone/widgets/customAppBar.dart';
8 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
9 | import 'package:flutter_twitter_clone/widgets/newWidget/rippleButton.dart';
10 | import 'package:flutter_twitter_clone/widgets/newWidget/title_text.dart';
11 | import 'package:provider/provider.dart';
12 |
13 | class SearchPage extends StatefulWidget {
14 | const SearchPage({Key key, this.scaffoldKey}) : super(key: key);
15 |
16 | final GlobalKey scaffoldKey;
17 |
18 | @override
19 | State createState() => _SearchPageState();
20 | }
21 |
22 | class _SearchPageState extends State {
23 | @override
24 | void initState() {
25 | WidgetsBinding.instance.addPostFrameCallback((_) {
26 | final state = Provider.of(context, listen: false);
27 | state.resetFilterList();
28 | });
29 | super.initState();
30 | }
31 |
32 | void onSettingIconPressed() {
33 | Navigator.pushNamed(context, '/TrendsPage');
34 | }
35 |
36 | @override
37 | Widget build(BuildContext context) {
38 | final state = Provider.of(context);
39 | final list = state.userlist;
40 | return Scaffold(
41 | appBar: CustomAppBar(
42 | scaffoldKey: widget.scaffoldKey,
43 | icon: AppIcon.settings,
44 | onActionPressed: onSettingIconPressed,
45 | onSearchChanged: (text) {
46 | state.filterByUsername(text);
47 | },
48 | ),
49 | body: RefreshIndicator(
50 | onRefresh: () async {
51 | state.getDataFromDatabase();
52 | return Future.value(true);
53 | },
54 | child: ListView.separated(
55 | addAutomaticKeepAlives: false,
56 | physics: BouncingScrollPhysics(),
57 | itemBuilder: (context, index) => _UserTile(user: list[index]),
58 | separatorBuilder: (_, index) => Divider(
59 | height: 0,
60 | ),
61 | itemCount: list?.length ?? 0,
62 | ),
63 | ),
64 | );
65 | }
66 | }
67 |
68 | class _UserTile extends StatelessWidget {
69 | const _UserTile({Key key, this.user}) : super(key: key);
70 | final UserModel user;
71 |
72 | @override
73 | Widget build(BuildContext context) {
74 | return RippleButton(
75 | onPressed: () {
76 | kAnalytics.logViewSearchResults(searchTerm: user.userName);
77 | Navigator.of(context).pushNamed('/ProfilePage/' + user?.userId);
78 | },
79 | child: Container(
80 | color: TwitterColor.white,
81 | child: ListTile(
82 | leading: customImage(context, user.profilePic, height: 40),
83 | title: Row(
84 | crossAxisAlignment: CrossAxisAlignment.start,
85 | children: [
86 | Flexible(
87 | child: TitleText(user.displayName,
88 | fontSize: 16,
89 | fontWeight: FontWeight.w800,
90 | overflow: TextOverflow.ellipsis),
91 | ),
92 | SizedBox(width: 3),
93 | user.isVerified
94 | ? customIcon(
95 | context,
96 | icon: AppIcon.blueTick,
97 | istwitterIcon: true,
98 | iconColor: AppColor.primary,
99 | size: 13,
100 | paddingIcon: 3,
101 | )
102 | : SizedBox(width: 0),
103 | ],
104 | ),
105 | subtitle: Text(user.userName),
106 | ),
107 | ),
108 | );
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/lib/page/Auth/selectAuthMethod.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/enum.dart';
3 | import 'package:flutter_twitter_clone/helper/theme.dart';
4 | import 'package:flutter_twitter_clone/page/Auth/signup.dart';
5 | import 'package:flutter_twitter_clone/state/authState.dart';
6 | import 'package:flutter_twitter_clone/widgets/newWidget/title_text.dart';
7 | import 'package:provider/provider.dart';
8 | import '../homePage.dart';
9 | import 'signin.dart';
10 |
11 | class WelcomePage extends StatefulWidget {
12 | WelcomePage({Key key}) : super(key: key);
13 |
14 | @override
15 | _WelcomePageState createState() => _WelcomePageState();
16 | }
17 |
18 | class _WelcomePageState extends State {
19 | Widget _submitButton() {
20 | return Container(
21 | margin: EdgeInsets.symmetric(vertical: 15),
22 | width: MediaQuery.of(context).size.width,
23 | child: FlatButton(
24 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
25 | color: TwitterColor.dodgetBlue,
26 | onPressed: () {
27 | var state = Provider.of(context,listen: false);
28 | Navigator.push(
29 | context,
30 | MaterialPageRoute(
31 | builder: (context) => Signup(loginCallback: state.getCurrentUser),
32 | ),
33 | );
34 | },
35 | padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10),
36 | child: TitleText('Create account', color: Colors.white),
37 | ),
38 | );
39 | }
40 |
41 | Widget _body() {
42 | return SafeArea(
43 | child: Container(
44 | padding: EdgeInsets.symmetric(
45 | horizontal: 40,
46 | ),
47 | child: Column(
48 | crossAxisAlignment: CrossAxisAlignment.start,
49 | children: [
50 | Container(
51 | width: MediaQuery.of(context).size.width - 80,
52 | height: 40,
53 | child: Image.asset('assets/images/icon-480.png'),
54 | ),
55 | Spacer(),
56 | TitleText(
57 | 'See what\'s happening in the world right now.',
58 | fontSize: 25,
59 | ),
60 | SizedBox(
61 | height: 20,
62 | ),
63 | _submitButton(),
64 | Spacer(),
65 | Wrap(
66 | alignment: WrapAlignment.center,
67 | crossAxisAlignment: WrapCrossAlignment.center,
68 | children: [
69 | TitleText(
70 | 'Have an account already?',
71 | fontSize: 14,
72 | fontWeight: FontWeight.w300,
73 | ),
74 | InkWell(
75 | onTap: () {
76 | var state = Provider.of(context,listen: false);
77 | Navigator.push(
78 | context,
79 | MaterialPageRoute(
80 | builder: (context) =>
81 | SignIn(loginCallback: state.getCurrentUser),
82 | ),
83 | );
84 | },
85 | child: Padding(
86 | padding: EdgeInsets.symmetric(horizontal: 2, vertical: 10),
87 | child: TitleText(
88 | ' Log in',
89 | fontSize: 14,
90 | color: TwitterColor.dodgetBlue,
91 | fontWeight: FontWeight.w300,
92 | ),
93 | ),
94 | )
95 | ],
96 | ),
97 | SizedBox(height: 20)
98 | ],
99 | ),
100 | ),
101 | );
102 | }
103 |
104 | @override
105 | Widget build(BuildContext context) {
106 | var state = Provider.of(context,listen: false);
107 | return Scaffold(
108 | body: state.authStatus == AuthStatus.NOT_LOGGED_IN ||
109 | state.authStatus == AuthStatus.NOT_DETERMINED
110 | ? _body()
111 | : HomePage(),
112 | );
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/lib/page/message/conversationInformation/conversationInformation.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/constant.dart';
3 | import 'package:flutter_twitter_clone/helper/theme.dart';
4 | import 'package:flutter_twitter_clone/model/user.dart';
5 | import 'package:flutter_twitter_clone/page/settings/widgets/headerWidget.dart';
6 | import 'package:flutter_twitter_clone/page/settings/widgets/settingsRowWidget.dart';
7 | import 'package:flutter_twitter_clone/state/chats/chatUserState.dart';
8 | import 'package:flutter_twitter_clone/widgets/customAppBar.dart';
9 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
10 | import 'package:flutter_twitter_clone/widgets/newWidget/customUrlText.dart';
11 | import 'package:flutter_twitter_clone/widgets/newWidget/rippleButton.dart';
12 | import 'package:provider/provider.dart';
13 |
14 | class ConversationInformation extends StatelessWidget {
15 | const ConversationInformation({Key key}) : super(key: key);
16 |
17 | Widget _header(BuildContext context, UserModel user) {
18 | return Padding(
19 | padding: EdgeInsets.symmetric(vertical: 25),
20 | child: Column(
21 | children: [
22 | Container(
23 | alignment: Alignment.center,
24 | child: SizedBox(
25 | height: 80,
26 | width: 80,
27 | child: RippleButton(
28 | onPressed: () {
29 | Navigator.of(context)
30 | .pushNamed('/ProfilePage/' + user?.userId);
31 | },
32 | borderRadius: BorderRadius.circular(40),
33 | child: customImage(context, user.profilePic, height: 80),
34 | )),
35 | ),
36 | Row(
37 | mainAxisAlignment: MainAxisAlignment.center,
38 | children: [
39 | UrlText(
40 | text: user.displayName,
41 | style: onPrimaryTitleText.copyWith(
42 | color: Colors.black,
43 | fontSize: 20,
44 | ),
45 | ),
46 | SizedBox(
47 | width: 3,
48 | ),
49 | user.isVerified
50 | ? customIcon(
51 | context,
52 | icon: AppIcon.blueTick,
53 | istwitterIcon: true,
54 | iconColor: AppColor.primary,
55 | size: 18,
56 | paddingIcon: 3,
57 | )
58 | : SizedBox(width: 0),
59 | ],
60 | ),
61 | customText(
62 | user.userName,
63 | style: onPrimarySubTitleText.copyWith(
64 | color: Colors.black54,
65 | fontSize: 15,
66 | ),
67 | ),
68 | ],
69 | ),
70 | );
71 | }
72 |
73 | @override
74 | Widget build(BuildContext context) {
75 | var user = Provider.of(context).chatUser ?? UserModel();
76 | return Scaffold(
77 | backgroundColor: TwitterColor.white,
78 | appBar: CustomAppBar(
79 | isBackButton: true,
80 | title: customTitleText(
81 | 'Conversation information',
82 | ),
83 | ),
84 | body: ListView(
85 | children: [
86 | _header(context, user),
87 | HeaderWidget('Notifications'),
88 | SettingRowWidget(
89 | "Mute conversation",
90 | visibleSwitch: true,
91 | ),
92 | Container(
93 | height: 15,
94 | color: TwitterColor.mystic,
95 | ),
96 | SettingRowWidget(
97 | "Block ${user.userName}",
98 | textColor: TwitterColor.dodgetBlue,
99 | showDivider: false,
100 | ),
101 | SettingRowWidget("Report ${user.userName}",
102 | textColor: TwitterColor.dodgetBlue, showDivider: false),
103 | SettingRowWidget("Delete conversation",
104 | textColor: TwitterColor.ceriseRed, showDivider: false),
105 | ],
106 | ),
107 | );
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/lib/model/user.dart:
--------------------------------------------------------------------------------
1 | class UserModel {
2 | String key;
3 | String email;
4 | String userId;
5 | String displayName;
6 | String userName;
7 | String webSite;
8 | String profilePic;
9 | String contact;
10 | String bio;
11 | String location;
12 | String dob;
13 | String createdAt;
14 | bool isVerified;
15 | int followers;
16 | int following;
17 | String fcmToken;
18 | List followersList;
19 | List followingList;
20 |
21 | UserModel({
22 | this.email,
23 | this.userId,
24 | this.displayName,
25 | this.profilePic,
26 | this.key,
27 | this.contact,
28 | this.bio,
29 | this.dob,
30 | this.location,
31 | this.createdAt,
32 | this.userName,
33 | this.followers,
34 | this.following,
35 | this.webSite,
36 | this.isVerified,
37 | this.fcmToken,
38 | this.followersList,
39 | });
40 |
41 | UserModel.fromJson(Map map) {
42 | if (map == null) {
43 | return;
44 | }
45 | if (followersList == null) {
46 | followersList = [];
47 | }
48 | email = map['email'];
49 | userId = map['userId'];
50 | displayName = map['displayName'];
51 | profilePic = map['profilePic'];
52 | key = map['key'];
53 | dob = map['dob'];
54 | bio = map['bio'];
55 | location = map['location'];
56 | contact = map['contact'];
57 | createdAt = map['createdAt'];
58 | followers = map['followers'];
59 | following = map['following'];
60 | userName = map['userName'];
61 | webSite = map['webSite'];
62 | fcmToken = map['fcmToken'];
63 | isVerified = map['isVerified'] ?? false;
64 | if (map['followerList'] != null) {
65 | followersList = List();
66 | map['followerList'].forEach((value) {
67 | followersList.add(value);
68 | });
69 | }
70 | followers = followersList != null ? followersList.length : null;
71 | if (map['followingList'] != null) {
72 | followingList = List();
73 | map['followingList'].forEach((value) {
74 | followingList.add(value);
75 | });
76 | }
77 | following = followingList != null ? followingList.length : null;
78 | }
79 | toJson() {
80 | return {
81 | 'key': key,
82 | "userId": userId,
83 | "email": email,
84 | 'displayName': displayName,
85 | 'profilePic': profilePic,
86 | 'contact': contact,
87 | 'dob': dob,
88 | 'bio': bio,
89 | 'location': location,
90 | 'createdAt': createdAt,
91 | 'followers': followersList != null ? followersList.length : null,
92 | 'following': followingList != null ? followingList.length : null,
93 | 'userName': userName,
94 | 'webSite': webSite,
95 | 'isVerified': isVerified ?? false,
96 | 'fcmToken': fcmToken,
97 | 'followerList': followersList,
98 | 'followingList': followingList
99 | };
100 | }
101 |
102 | UserModel copyWith({
103 | String email,
104 | String userId,
105 | String displayName,
106 | String profilePic,
107 | String key,
108 | String contact,
109 | bio,
110 | String dob,
111 | String location,
112 | String createdAt,
113 | String userName,
114 | int followers,
115 | int following,
116 | String webSite,
117 | bool isVerified,
118 | String fcmToken,
119 | List followingList,
120 | }) {
121 | return UserModel(
122 | email: email ?? this.email,
123 | bio: bio ?? this.bio,
124 | contact: contact ?? this.contact,
125 | createdAt: createdAt ?? this.createdAt,
126 | displayName: displayName ?? this.displayName,
127 | dob: dob ?? this.dob,
128 | followers: followersList != null ? followersList.length : null,
129 | following: following ?? this.following,
130 | isVerified: isVerified ?? this.isVerified,
131 | key: key ?? this.key,
132 | location: location ?? this.location,
133 | profilePic: profilePic ?? this.profilePic,
134 | userId: userId ?? this.userId,
135 | userName: userName ?? this.userName,
136 | webSite: webSite ?? this.webSite,
137 | fcmToken: fcmToken ?? this.fcmToken,
138 | followersList: followersList ?? this.followersList,
139 | );
140 | }
141 |
142 | String getFollower() {
143 | return '${this.followers ?? 0}';
144 | }
145 |
146 | String getFollowing() {
147 | return '${this.following ?? 0}';
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/lib/helper/theme.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 |
4 | List shadow = [BoxShadow(blurRadius: 10,offset: Offset(5, 5),color: AppTheme.apptheme.accentColor,spreadRadius:1)];
5 | String get description { return '';}
6 | TextStyle get onPrimaryTitleText { return TextStyle(color: Colors.white,fontWeight: FontWeight.w600);}
7 | TextStyle get onPrimarySubTitleText { return TextStyle(color: Colors.white,);}
8 | BoxDecoration softDecoration = BoxDecoration(
9 | boxShadow: [
10 | BoxShadow(blurRadius: 8,offset: Offset(5, 5),color: Color(0xffe2e5ed),spreadRadius:5),
11 | BoxShadow(blurRadius: 8,offset: Offset(-5,-5),color: Color(0xffffffff),spreadRadius:5)
12 | ],
13 | color: Color(0xfff1f3f6)
14 | );
15 | TextStyle get titleStyle { return TextStyle(color: Colors.black,fontSize: 16,fontWeight: FontWeight.bold,);}
16 | TextStyle get subtitleStyle { return TextStyle(color: AppColor.darkGrey,fontSize: 14,fontWeight: FontWeight.bold);}
17 | TextStyle get userNameStyle { return TextStyle(color: AppColor.darkGrey,fontSize: 14,fontWeight: FontWeight.bold);}
18 | TextStyle get textStyle14 { return TextStyle(color: AppColor.darkGrey,fontSize: 14,fontWeight: FontWeight.bold);}
19 |
20 | class TwitterColor {
21 | static final Color bondiBlue = Color.fromRGBO(0, 132, 180, 1.0);
22 | static final Color cerulean = Color.fromRGBO(0, 172, 237, 1.0);
23 | static final Color spindle = Color.fromRGBO(192, 222, 237, 1.0);
24 | static final Color white = Color.fromRGBO(255, 255, 255, 1.0);
25 | static final Color black = Color.fromRGBO(0, 0, 0, 1.0);
26 | static final Color woodsmoke = Color.fromRGBO(20, 23, 2, 1.0);
27 | static final Color woodsmoke_50 = Color.fromRGBO(20, 23, 2, 0.5);
28 | static final Color mystic = Color.fromRGBO(230, 236, 240, 1.0);
29 | static final Color dodgetBlue = Color.fromRGBO(29, 162, 240, 1.0);
30 | static final Color dodgetBlue_50 = Color.fromRGBO(29, 162, 240, 0.5);
31 | static final Color paleSky = Color.fromRGBO(101, 119, 133, 1.0);
32 | static final Color ceriseRed = Color.fromRGBO(224, 36, 94, 1.0);
33 | static final Color paleSky50 = Color.fromRGBO(101, 118, 133, 0.5);
34 | }
35 |
36 | class AppColor{
37 | static final Color primary = Color(0xff1DA1F2);
38 | static final Color secondary = Color(0xff14171A);
39 | static final Color darkGrey = Color(0xff1657786);
40 | static final Color lightGrey = Color(0xffAAB8C2);
41 | static final Color extraLightGrey = Color(0xffE1E8ED);
42 | static final Color extraExtraLightGrey = Color(0xfF5F8FA);
43 | static final Color white = Color(0xFFffffff);
44 | }
45 | class AppTheme{
46 | static final ThemeData apptheme = ThemeData(
47 | primarySwatch: Colors.blue,
48 | // fontFamily: 'HelveticaNeue',
49 | backgroundColor: TwitterColor.white,
50 | accentColor: TwitterColor.dodgetBlue,
51 | brightness: Brightness.light,
52 | primaryColor: AppColor.primary,
53 | cardColor: Colors.white,
54 | unselectedWidgetColor: Colors.grey,
55 | bottomAppBarColor: Colors.white,
56 | bottomSheetTheme: BottomSheetThemeData(
57 | backgroundColor: AppColor.white
58 | ),
59 | appBarTheme: AppBarTheme(
60 | brightness: Brightness.light,
61 | color: TwitterColor.white,
62 | iconTheme: IconThemeData(color: TwitterColor.dodgetBlue,),
63 | elevation: 0,
64 | textTheme: TextTheme(
65 | title: TextStyle(
66 | color: Colors.black,
67 | fontSize: 26,
68 | fontStyle: FontStyle.normal),
69 | )),
70 | tabBarTheme: TabBarTheme(
71 | labelStyle: titleStyle.copyWith(color: TwitterColor.dodgetBlue),
72 | unselectedLabelColor: AppColor.darkGrey,
73 | unselectedLabelStyle: titleStyle.copyWith(color: AppColor.darkGrey),
74 | labelColor: TwitterColor.dodgetBlue,
75 | labelPadding: EdgeInsets.symmetric(vertical: 12),
76 | ),
77 | floatingActionButtonTheme: FloatingActionButtonThemeData(
78 | backgroundColor: TwitterColor.dodgetBlue,
79 | ),
80 | colorScheme: ColorScheme(
81 | background: Colors.white,
82 | onPrimary: Colors.white,
83 | onBackground: Colors.black,
84 | onError: Colors.white,
85 | onSecondary: Colors.white,
86 | onSurface: Colors.black,
87 | error: Colors.red,
88 | primary: Colors.blue,
89 | primaryVariant: Colors.blue,
90 | secondary: AppColor.secondary,
91 | secondaryVariant: AppColor.darkGrey,
92 | surface: Colors.white,
93 | brightness: Brightness.light
94 | )
95 | );
96 | }
--------------------------------------------------------------------------------
/lib/page/message/newMessagePage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/constant.dart';
3 | import 'package:flutter_twitter_clone/helper/theme.dart';
4 | import 'package:flutter_twitter_clone/model/user.dart';
5 | import 'package:flutter_twitter_clone/state/chats/chatUserState.dart';
6 | import 'package:flutter_twitter_clone/state/searchState.dart';
7 | import 'package:flutter_twitter_clone/widgets/customAppBar.dart';
8 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
9 | import 'package:flutter_twitter_clone/widgets/newWidget/title_text.dart';
10 | import 'package:provider/provider.dart';
11 |
12 | class NewMessagePage extends StatefulWidget {
13 | const NewMessagePage({Key key, this.scaffoldKey}) : super(key: key);
14 |
15 | final GlobalKey scaffoldKey;
16 |
17 | @override
18 | State createState() => _NewMessagePageState();
19 | }
20 |
21 | class _NewMessagePageState extends State {
22 | TextEditingController textController;
23 |
24 | @override
25 | void initState() {
26 | textController = TextEditingController();
27 | super.initState();
28 | }
29 |
30 | Widget _userTile(UserModel user) {
31 | return ListTile(
32 | onTap: () {
33 | final chatState = Provider.of(context, listen: false);
34 | chatState.setChatUser = user;
35 | Navigator.pushNamed(context, '/ChatScreenPage');
36 | },
37 | leading: customImage(context, user.profilePic, height: 40),
38 | title: Row(
39 | children: [
40 | ConstrainedBox(
41 | constraints:
42 | BoxConstraints(minWidth: 0, maxWidth: fullWidth(context) - 104),
43 | child: TitleText(user.displayName,
44 | fontSize: 16,
45 | fontWeight: FontWeight.w800,
46 | overflow: TextOverflow.ellipsis),
47 | ),
48 | SizedBox(width: 3),
49 | user.isVerified
50 | ? customIcon(context,
51 | icon: AppIcon.blueTick,
52 | istwitterIcon: true,
53 | iconColor: AppColor.primary,
54 | size: 13,
55 | paddingIcon: 3)
56 | : SizedBox(width: 0),
57 | ],
58 | ),
59 | subtitle: Text(user.userName),
60 | );
61 | }
62 |
63 | Future _onWillPop() async {
64 | final state = Provider.of(context, listen: false);
65 | state.filterByUsername("");
66 | return true;
67 | }
68 |
69 | @override
70 | Widget build(BuildContext context) {
71 | return WillPopScope(
72 | onWillPop: _onWillPop,
73 | child: Scaffold(
74 | appBar: CustomAppBar(
75 | scaffoldKey: widget.scaffoldKey,
76 | isBackButton: true,
77 | isbootomLine: true,
78 | title: customTitleText(
79 | 'New Message',
80 | ),
81 | ),
82 | body: Consumer(
83 | builder: (context, state, child) {
84 | return Column(
85 | children: [
86 | TextField(
87 | onChanged: (text) {
88 | state.filterByUsername(text);
89 | },
90 | decoration: InputDecoration(
91 | hintText: "Search for people and groups",
92 | hintStyle: TextStyle(fontSize: 20),
93 | prefixIcon: customIcon(
94 | context,
95 | icon: AppIcon.search,
96 | istwitterIcon: true,
97 | iconColor: TwitterColor.woodsmoke_50,
98 | size: 25,
99 | paddingIcon: 5,
100 | ),
101 | border: InputBorder.none,
102 | fillColor: TwitterColor.mystic,
103 | filled: true,
104 | ),
105 | ),
106 | Expanded(
107 | child: ListView.separated(
108 | physics: BouncingScrollPhysics(),
109 | itemBuilder: (context, index) => _userTile(
110 | state.userlist[index],
111 | ),
112 | separatorBuilder: (_, index) => Divider(
113 | height: 0,
114 | ),
115 | itemCount: state.userlist.length,
116 | ),
117 | )
118 | ],
119 | );
120 | },
121 | ),
122 | ),
123 | );
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_twitter_clone
2 | description: A new Flutter project.
3 |
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # In Android, build-name is used as versionName while build-number used as versionCode.
10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
12 | # Read more about iOS versioning at
13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
14 | version: 1.0.5+10
15 |
16 | environment:
17 | sdk: ">=2.1.0 <3.0.0"
18 |
19 | dependencies:
20 | flutter:
21 | sdk: flutter
22 |
23 | # The following adds the Cupertino Icons font to your application.
24 | # Use with the CupertinoIcons class for iOS style icons.
25 | cupertino_icons: ^0.1.2
26 | # empty_widget:
27 | # flutter_advanced_networkimage:
28 | cached_network_image: ^2.2.0+1
29 | provider: ^4.3.2+2
30 | # flutter_native_splash: ^0.1.9
31 | firebase_auth: ^0.18.3
32 | firebase_database:
33 | firebase_analytics:
34 |
35 | cloud_firestore:
36 | firebase_storage:
37 | image_picker: ^0.6.2
38 | uuid: ^2.0.0
39 | http:
40 | shared_preferences: ^0.5.1+2
41 | firebase_messaging: ^6.0.13
42 | google_sign_in: "^4.5.1"
43 | intl: ^0.16.1
44 | url_launcher:
45 | share: ^0.6.3
46 | google_fonts: ^0.3.9
47 | firebase_remote_config: ^0.3.0+3
48 |
49 | # camera:
50 | # image: ^2.0.75
51 | # path_provider: ^0.5.0+1
52 | # location: ^2.3.3
53 | # geocoder: ^0.1.2
54 | dev_dependencies:
55 | test:
56 | flutter_test:
57 | sdk: flutter
58 | flutter_launcher_icons: "^0.7.3"
59 |
60 | flutter_icons:
61 | ios: true
62 | android: true
63 | image_path_ios: "assets/images/icon-400.png"
64 | image_path_android: "assets/images/icon-400.png"
65 | # For information on the generic Dart part of this file, see the
66 | # following page: https://dart.dev/tools/pub/pubspec
67 |
68 | # The following section is specific to Flutter.
69 | flutter:
70 |
71 | # The following line ensures that the Material Icons font is
72 | # included with your application, so that you can use the icons in
73 | # the material Icons class.
74 | uses-material-design: true
75 |
76 | # To add assets to your application, add an assets section, like this:
77 | assets:
78 | - assets/images/icon-48.png
79 | - assets/images/icon-480.png
80 | - assets/images/icon-400.png
81 | - assets/images/qr.png
82 | - assets/images/bulb.png
83 | - assets/images/google_logo.png
84 |
85 | # An image asset can refer to one or more resolution-specific "variants", see
86 | # https://flutter.dev/assets-and-images/#resolution-aware.
87 |
88 | # For details regarding adding assets from package dependencies, see
89 | # https://flutter.dev/assets-and-images/#from-packages
90 |
91 | # To add custom fonts to your application, add a fonts section here,
92 | # in this "flutter" section. Each entry in this list should have a
93 | # "family" key with the font family name, and a "fonts" key with a
94 | # list giving the asset and other descriptors for the font. For
95 | # example:
96 | fonts:
97 | - family: TwitterIcon
98 | fonts:
99 | - asset: assets/fonts/icons.ttf
100 | - family: HelveticaNeue
101 | fonts:
102 | - asset: assets/fonts/HelveticaNeue.ttf
103 | - asset: assets/fonts/HelveticaNeue400.ttf
104 | weight: 400
105 | - asset: assets/fonts/HelveticaNeue500.ttf
106 | weight: 500
107 | - asset: assets/fonts/HelveticaNeue600.ttf
108 | weight: 600
109 | - asset: assets/fonts/HelveticaNeue700.ttf
110 | weight: 700
111 | - asset: assets/fonts/HelveticaNeue800.ttf
112 | weight: 800
113 | - asset: assets/fonts/HelveticaNeue900.ttf
114 | weight: 900
115 | - asset: assets/fonts/HelveticaNeueIt.ttf
116 | style: italic
117 |
118 | # - asset: fonts/Schyler-Italic.ttf
119 | # style: italic
120 | # - family: Trajan Pro
121 | # fonts:
122 | # - asset: fonts/TrajanPro.ttf
123 | # - asset: fonts/TrajanPro_Bold.ttf
124 | # weight: 700
125 | #
126 | # For details regarding fonts from package dependencies,
127 | # see https://flutter.dev/custom-fonts/#from-packages
128 |
--------------------------------------------------------------------------------
/lib/page/settings/accountSettings/contentPrefrences/trends/trendsPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/enum.dart';
3 | import 'package:flutter_twitter_clone/helper/theme.dart';
4 | import 'package:flutter_twitter_clone/page/settings/widgets/settingsRowWidget.dart';
5 | import 'package:flutter_twitter_clone/state/searchState.dart';
6 | import 'package:flutter_twitter_clone/widgets/customAppBar.dart';
7 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
8 | import 'package:flutter_twitter_clone/widgets/newWidget/title_text.dart';
9 | import 'package:provider/provider.dart';
10 |
11 | class TrendsPage extends StatelessWidget {
12 | String sortBy = "";
13 |
14 | TrendsPage({Key key}) : super(key: key);
15 |
16 | void openBottomSheet(
17 | BuildContext context, double height, Widget child) async {
18 | await showModalBottomSheet(
19 | backgroundColor: Colors.transparent,
20 | context: context,
21 | builder: (context) {
22 | return Container(
23 | height: height,
24 | decoration: BoxDecoration(
25 | color: TwitterColor.white,
26 | borderRadius: BorderRadius.only(
27 | topLeft: Radius.circular(15),
28 | topRight: Radius.circular(15),
29 | ),
30 | ),
31 | child: child,
32 | );
33 | },
34 | );
35 | }
36 |
37 | void openUserSortSettings(BuildContext context) {
38 | openBottomSheet(
39 | context,
40 | 340,
41 | Column(
42 | children: [
43 | SizedBox(height: 5),
44 | Container(
45 | width: 40,
46 | height: 5,
47 | decoration: BoxDecoration(
48 | color: TwitterColor.paleSky50,
49 | borderRadius: BorderRadius.circular(10),
50 | ),
51 | ),
52 | Padding(
53 | padding: EdgeInsets.symmetric(vertical: 10),
54 | child: TitleText('Sort user list'),
55 | ),
56 | Divider(height: 0),
57 | _row(context, "Verified user first", SortUser.ByVerified),
58 | Divider(height: 0),
59 | _row(context, "alphabetically", SortUser.ByAlphabetically),
60 | Divider(height: 0),
61 | _row(context, "Newest user first", SortUser.ByNewest),
62 | Divider(height: 0),
63 | _row(context, "Oldest user first", SortUser.ByOldest),
64 | Divider(height: 0),
65 | _row(context, "User with max follower", SortUser.ByMaxFollower),
66 | ],
67 | ),
68 | );
69 | }
70 |
71 | Widget _row(BuildContext context, String text, SortUser sortBy) {
72 | final state = Provider.of(context);
73 | return Padding(
74 | padding: EdgeInsets.symmetric(vertical: 0, horizontal: 5),
75 | child: RadioListTile(
76 | value: sortBy,
77 | activeColor: TwitterColor.dodgetBlue,
78 | groupValue: state.sortBy,
79 | onChanged: (val) {
80 | state.updateUserSortPrefrence = val;
81 | Navigator.pop(context);
82 | },
83 | title: Text(text, style: subtitleStyle),
84 | controlAffinity: ListTileControlAffinity.trailing,
85 | ),
86 | );
87 | }
88 |
89 | @override
90 | Widget build(BuildContext context) {
91 | WidgetsBinding.instance.addPostFrameCallback((_) {
92 | final state = Provider.of(context);
93 | sortBy = state.selectedFilter;
94 | });
95 | return Scaffold(
96 | backgroundColor: TwitterColor.white,
97 | appBar: CustomAppBar(
98 | isBackButton: true,
99 | title: customTitleText(
100 | 'Trends',
101 | ),
102 | ),
103 | body: ListView(
104 | physics: BouncingScrollPhysics(),
105 | children: [
106 | SettingRowWidget(
107 | "Search Filter",
108 | subtitle: sortBy,
109 | onPressed: () {
110 | openUserSortSettings(context);
111 | },
112 | showDivider: false,
113 | ),
114 | SettingRowWidget(
115 | "Trends location",
116 | navigateTo: null,
117 | subtitle: 'New York',
118 | showDivider: false,
119 | ),
120 | SettingRowWidget(
121 | null,
122 | subtitle:
123 | 'You can see what\'s trending in a specfic location by selecting which location appears in your Trending tab.',
124 | navigateTo: null,
125 | showDivider: false,
126 | vPadding: 12,
127 | ),
128 | ],
129 | ),
130 | );
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/lib/page/Auth/forgetPasswordPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/helper/utility.dart';
4 | import 'package:flutter_twitter_clone/state/authState.dart';
5 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
6 | import 'package:provider/provider.dart';
7 | class ForgetPasswordPage extends StatefulWidget{
8 | final VoidCallback loginCallback;
9 |
10 | const ForgetPasswordPage({Key key, this.loginCallback}) : super(key: key);
11 | @override
12 | State createState() => _ForgetPasswordPageState();
13 |
14 | }
15 |
16 | class _ForgetPasswordPageState extends State{
17 | FocusNode _focusNode;
18 | TextEditingController _emailController;
19 | final GlobalKey _scaffoldKey = new GlobalKey();
20 | @override
21 | void initState() {
22 | _focusNode = FocusNode();
23 | _emailController = TextEditingController();
24 | _emailController.text = '';
25 | _focusNode.requestFocus();
26 | super.initState();
27 | }
28 | @override
29 | void dispose(){
30 | _focusNode.dispose();
31 | super.dispose();
32 | }
33 | Widget _body(BuildContext context){
34 | return Container(
35 | height: fullHeight(context),
36 | padding: EdgeInsets.symmetric(horizontal: 30),
37 | child:Column(
38 | mainAxisAlignment: MainAxisAlignment.center,
39 | crossAxisAlignment: CrossAxisAlignment.center,
40 | children: [
41 | _label(),
42 | SizedBox(height: 50,),
43 | _entryFeild('Enter email',controller: _emailController),
44 | // SizedBox(height: 10,),
45 | _submitButton(context),
46 | ],)
47 | );
48 | }
49 | Widget _entryFeild(String hint,{TextEditingController controller,bool isPassword = false}){
50 | return Container(
51 | margin: EdgeInsets.symmetric(vertical: 15),
52 | decoration: BoxDecoration(
53 | color: Colors.grey.shade200,
54 | borderRadius: BorderRadius.circular(30)
55 | ),
56 | child: TextField(
57 | focusNode: _focusNode,
58 | controller: controller,
59 | keyboardType: TextInputType.emailAddress,
60 | style: TextStyle(fontStyle: FontStyle.normal,fontWeight: FontWeight.normal),
61 | obscureText: isPassword,
62 | decoration: InputDecoration(
63 | hintText: hint,
64 |
65 | border: InputBorder.none,
66 | focusedBorder: OutlineInputBorder(
67 | borderRadius: BorderRadius.all(Radius.circular(30.0)),
68 | borderSide: BorderSide(color: Colors.blue)),
69 | contentPadding:EdgeInsets.symmetric(vertical: 15,horizontal: 10)
70 | ),
71 | ),
72 | );
73 | }
74 | Widget _submitButton(BuildContext context){
75 | return Container(
76 | margin: EdgeInsets.symmetric(vertical: 15),
77 | width: MediaQuery.of(context).size.width,
78 | child: FlatButton(
79 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
80 | color: TwitterColor.dodgetBlue,
81 | onPressed:_submit,
82 | padding: EdgeInsets.symmetric(horizontal: 30,vertical: 10),
83 | child: Text('Submit',style:TextStyle(color: Colors.white)),
84 | )
85 | );
86 | }
87 | Widget _label(){
88 | return Container(
89 | child:Column(
90 | children: [
91 | customText('Forget Password',style:TextStyle(fontSize: 24,fontWeight: FontWeight.bold)),
92 | SizedBox(height: 15),
93 | Padding(
94 | padding: EdgeInsets.symmetric(horizontal: 20),
95 | child: customText('Enter your email address below to receive password reset instruction',
96 | style:TextStyle(fontSize: 18,fontWeight: FontWeight.w500,color: Colors.black54),textAlign: TextAlign.center),
97 |
98 | )
99 | ],
100 | )
101 | );
102 | }
103 | void _submit(){
104 | if(_emailController.text == null || _emailController.text.isEmpty){
105 | customSnackBar(_scaffoldKey, 'Email field cannot be empty');
106 | return;
107 | }
108 | var isValidEmail = validateEmal(_emailController.text, );
109 | if(!isValidEmail){
110 | customSnackBar(_scaffoldKey, 'Please enter valid email address');
111 | return;
112 | }
113 |
114 | _focusNode.unfocus();
115 | var state = Provider.of(context,listen: false);
116 | state.forgetPassword(_emailController.text,scaffoldKey:_scaffoldKey);
117 | }
118 | @override
119 | Widget build(BuildContext context) {
120 | return Scaffold(
121 | key: _scaffoldKey,
122 | appBar: AppBar(
123 | title: customText('Forget Password',context: context,style: TextStyle(fontSize: 20)),
124 | centerTitle: true,
125 | ),
126 | body: _body(context),
127 | );
128 | }
129 |
130 | }
--------------------------------------------------------------------------------
/lib/page/settings/accountSettings/privacyAndSafety/privacyAndSafetyPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/model/user.dart';
4 | import 'package:flutter_twitter_clone/page/settings/widgets/headerWidget.dart';
5 | import 'package:flutter_twitter_clone/page/settings/widgets/settingsAppbar.dart';
6 | import 'package:flutter_twitter_clone/page/settings/widgets/settingsRowWidget.dart';
7 | import 'package:flutter_twitter_clone/state/authState.dart';
8 | import 'package:flutter_twitter_clone/widgets/newWidget/customUrlText.dart';
9 | import 'package:provider/provider.dart';
10 |
11 | class PrivacyAndSaftyPage extends StatelessWidget {
12 | const PrivacyAndSaftyPage({Key key}) : super(key: key);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | var user = Provider.of(context).userModel ?? UserModel();
17 | return Scaffold(
18 | backgroundColor: TwitterColor.white,
19 | appBar: SettingsAppBar(
20 | title: 'Privacy and safety',
21 | subtitle: user.userName,
22 | ),
23 | body: ListView(
24 | physics: BouncingScrollPhysics(),
25 | children: [
26 | HeaderWidget('Tweets'),
27 | SettingRowWidget(
28 | "Protect your tweet",
29 | subtitle:
30 | 'Only current followers and people you approve in future will be able to see your tweets.',
31 | vPadding: 15,
32 | showDivider: false,
33 | visibleSwitch: true,
34 | ),
35 | SettingRowWidget(
36 | "Photo tagging",
37 | subtitle: 'Anyone can tag you',
38 | ),
39 | HeaderWidget(
40 | 'Direct Message',
41 | secondHeader: true,
42 | ),
43 | SettingRowWidget(
44 | 'Direct Message',
45 | navigateTo: 'DirectMessagesPage',
46 | ),
47 | HeaderWidget(
48 | 'Live Video',
49 | secondHeader: true,
50 | ),
51 | SettingRowWidget(
52 | "Connect to Periscope",
53 | subtitle:
54 | 'If selected, you can go live and comment on Periscope broadcasts, and people will be able to see when you\'re watching. if this setting is off, people won\'t be able comment or broadcast live.',
55 | vPadding: 15,
56 | showDivider: false,
57 | visibleSwitch: true,
58 | ),
59 | HeaderWidget(
60 | 'Discoverability and contacts',
61 | secondHeader: true,
62 | ),
63 | SettingRowWidget(
64 | "Discoverability and contacts",
65 | vPadding: 15,
66 | showDivider: false,
67 | ),
68 | SettingRowWidget(
69 | null,
70 | subtitle:
71 | 'Learn more about how this data is used to connect you with people',
72 | vPadding: 15,
73 | showDivider: false,
74 | ),
75 | HeaderWidget(
76 | 'Safety',
77 | secondHeader: true,
78 | ),
79 | SettingRowWidget(
80 | "Display media that may contain sensitive content",
81 | vPadding: 15,
82 | showDivider: false,
83 | visibleSwitch: true,
84 | ),
85 | SettingRowWidget(
86 | "Mark media you tweet as containing material thta may be sensitive",
87 | vPadding: 15,
88 | showDivider: false,
89 | visibleSwitch: true,
90 | ),
91 | SettingRowWidget(
92 | "Blocked Accounts",
93 | showDivider: false,
94 | ),
95 | SettingRowWidget(
96 | "Muted Accounts",
97 | showDivider: false,
98 | ),
99 | SettingRowWidget(
100 | "Muted Words",
101 | showDivider: false,
102 | ),
103 | HeaderWidget(
104 | 'Location',
105 | secondHeader: true,
106 | ),
107 | SettingRowWidget(
108 | "Precise location",
109 | subtitle:
110 | 'Disabled \n\n\nIf enabled, Fwitter will collect, store, and use your device\'s precise location, such as your GPS information. This lets Fwitter improve your experience - for rxample, showing you mpre local content, ads, and recommendations.',
111 | ),
112 | HeaderWidget(
113 | 'Personalisation and data',
114 | secondHeader: true,
115 | ),
116 | SettingRowWidget(
117 | "Personalisation and data",
118 | subtitle: "Allow all",
119 | ),
120 | SettingRowWidget(
121 | "See your Fwitter data",
122 | subtitle:
123 | "Review and edit your profile information and data associated with your account.",
124 | ),
125 | ],
126 | ),
127 | );
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/lib/page/feed/composeTweet/widget/composeBottomIconWidget.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_twitter_clone/helper/constant.dart';
5 | import 'package:flutter_twitter_clone/helper/theme.dart';
6 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
7 | import 'package:image_picker/image_picker.dart';
8 |
9 | class ComposeBottomIconWidget extends StatefulWidget {
10 |
11 | final TextEditingController textEditingController;
12 | final Function(File) onImageIconSelcted;
13 | ComposeBottomIconWidget({Key key, this.textEditingController, this.onImageIconSelcted}) : super(key: key);
14 |
15 | @override
16 | _ComposeBottomIconWidgetState createState() => _ComposeBottomIconWidgetState();
17 | }
18 |
19 | class _ComposeBottomIconWidgetState extends State {
20 |
21 | bool reachToWarning = false;
22 | bool reachToOver = false;
23 | Color wordCountColor;
24 | String tweet = '';
25 |
26 | @override
27 | void initState() {
28 | wordCountColor = Colors.blue;
29 | widget.textEditingController.addListener(updateUI);
30 | super.initState();
31 | }
32 | void updateUI(){
33 | setState(() {
34 | tweet = widget.textEditingController.text;
35 | if (widget.textEditingController.text != null &&
36 | widget.textEditingController.text.isNotEmpty) {
37 | if (widget.textEditingController.text.length > 259 &&
38 | widget.textEditingController.text.length < 280) {
39 | wordCountColor = Colors.orange;
40 | } else if (widget.textEditingController.text.length >= 280) {
41 | wordCountColor = Theme.of(context).errorColor;
42 | } else {
43 | wordCountColor = Colors.blue;
44 | }
45 | }
46 | });
47 | }
48 | Widget _bottomIconWidget() {
49 | return Container(
50 | width: fullWidth(context),
51 | height: 50,
52 | decoration: BoxDecoration(
53 | border:
54 | Border(top: BorderSide(color: Theme.of(context).dividerColor)),
55 | color: Theme.of(context).backgroundColor),
56 | child: Row(
57 | children: [
58 | IconButton(
59 | onPressed: () {
60 | setImage(ImageSource.gallery);
61 | },
62 | icon: customIcon(context,
63 | icon: AppIcon.image,
64 | istwitterIcon: true,
65 | iconColor: AppColor.primary)),
66 | IconButton(
67 | onPressed: () {
68 | setImage(ImageSource.camera);
69 | },
70 | icon: customIcon(context,
71 | icon: AppIcon.camera,
72 | istwitterIcon: true,
73 | iconColor: AppColor.primary)),
74 | Expanded(
75 | child: Align(
76 | alignment: Alignment.centerRight,
77 | child: Padding(
78 | padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20),
79 | child: tweet != null &&
80 | tweet.length > 289
81 | ? Padding(
82 | padding: EdgeInsets.only(right: 10),
83 | child: customText(
84 | '${280 - tweet.length}',
85 | style:
86 | TextStyle(color: Theme.of(context).errorColor)),
87 | )
88 | : Stack(
89 | alignment: Alignment.center,
90 | children: [
91 | CircularProgressIndicator(
92 | value: getTweetLimit(),
93 | backgroundColor: Colors.grey,
94 | valueColor:
95 | AlwaysStoppedAnimation(wordCountColor),
96 | ),
97 | tweet.length > 259
98 | ? customText(
99 | '${280 - tweet.length}',
100 | style: TextStyle(color: wordCountColor))
101 | : customText('',
102 | style: TextStyle(color: wordCountColor))
103 | ],
104 | )),
105 | ))
106 | ],
107 | ),
108 | );
109 | }
110 | void setImage(ImageSource source) {
111 | ImagePicker.pickImage(source: source, imageQuality: 20).then((File file) {
112 | setState(() {
113 | // _image = file;
114 | widget.onImageIconSelcted(file);
115 | });
116 | });
117 | }
118 | double getTweetLimit() {
119 | if (tweet == null ||
120 | tweet.isEmpty) {
121 | return 0.0;
122 | }
123 | if (tweet.length > 280) {
124 | return 1.0;
125 | }
126 | var length = tweet.length;
127 | var val = length * 100 / 28000.0;
128 | return val;
129 | }
130 |
131 | @override
132 | Widget build(BuildContext context) {
133 | return Container(
134 | child: _bottomIconWidget(),
135 | );
136 | }
137 | }
--------------------------------------------------------------------------------
/lib/page/settings/accountSettings/accessibility/accessibility.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_twitter_clone/helper/theme.dart';
3 | import 'package:flutter_twitter_clone/page/settings/widgets/headerWidget.dart';
4 | import 'package:flutter_twitter_clone/page/settings/widgets/settingsRowWidget.dart';
5 | import 'package:flutter_twitter_clone/widgets/customAppBar.dart';
6 | import 'package:flutter_twitter_clone/widgets/customWidgets.dart';
7 | import 'package:flutter_twitter_clone/widgets/newWidget/title_text.dart';
8 |
9 | class AccessibilityPage extends StatelessWidget {
10 | const AccessibilityPage({Key key}) : super(key: key);
11 |
12 | void openBottomSheet(
13 | BuildContext context,
14 | double height,
15 | Widget child,
16 | ) async {
17 | await showModalBottomSheet(
18 | backgroundColor: Colors.transparent,
19 | context: context,
20 | builder: (context) {
21 | return Container(
22 | height: height,
23 | decoration: BoxDecoration(
24 | color: TwitterColor.white,
25 | borderRadius: BorderRadius.only(
26 | topLeft: Radius.circular(15),
27 | topRight: Radius.circular(15),
28 | ),
29 | ),
30 | child: child,
31 | );
32 | },
33 | );
34 | }
35 |
36 | void openDarkModeSettings(BuildContext context) {
37 | openBottomSheet(
38 | context,
39 | 250,
40 | Column(
41 | children: [
42 | SizedBox(height: 5),
43 | Container(
44 | width: 40,
45 | height: 5,
46 | decoration: BoxDecoration(
47 | color: TwitterColor.paleSky50,
48 | borderRadius: BorderRadius.circular(10),
49 | ),
50 | ),
51 | Padding(
52 | padding: EdgeInsets.symmetric(vertical: 15),
53 | child: TitleText('Data preference'),
54 | ),
55 | Divider(height: 0),
56 | _row("Mobile data & Wi-Fi"),
57 | Divider(height: 0),
58 | _row("Wi-Fi only"),
59 | Divider(height: 0),
60 | _row("Never"),
61 | ],
62 | ),
63 | );
64 | }
65 |
66 | void openDarkModeAppearanceSettings(BuildContext context) {
67 | openBottomSheet(
68 | context,
69 | 190,
70 | Column(
71 | children: [
72 | SizedBox(height: 5),
73 | Container(
74 | width: 40,
75 | height: 5,
76 | decoration: BoxDecoration(
77 | color: TwitterColor.paleSky50,
78 | borderRadius: BorderRadius.circular(10),
79 | ),
80 | ),
81 | Padding(
82 | padding: EdgeInsets.symmetric(vertical: 10),
83 | child: TitleText('Dark mode appearance'),
84 | ),
85 | Divider(height: 0),
86 | _row("Dim"),
87 | Divider(height: 0),
88 | _row("Light out"),
89 | ],
90 | ),
91 | );
92 | }
93 |
94 | Widget _row(String text) {
95 | return Padding(
96 | padding: EdgeInsets.symmetric(vertical: 0, horizontal: 5),
97 | child: RadioListTile(
98 | value: false,
99 | groupValue: true,
100 | onChanged: (val) {},
101 | title: Text(text),
102 | controlAffinity: ListTileControlAffinity.trailing,
103 | ),
104 | );
105 | }
106 |
107 | @override
108 | Widget build(BuildContext context) {
109 | return Scaffold(
110 | backgroundColor: TwitterColor.white,
111 | appBar: CustomAppBar(
112 | isBackButton: true,
113 | title: customTitleText(
114 | 'Accessibility',
115 | ),
116 | ),
117 | body: ListView(
118 | physics: BouncingScrollPhysics(),
119 | children: [
120 | HeaderWidget('Screen Reader'),
121 | SettingRowWidget(
122 | "Pronounce # as \"hashtag\"",
123 | showCheckBox: true,
124 | ),
125 | Divider(height: 0),
126 | HeaderWidget('Vision'),
127 | SettingRowWidget(
128 | "Compose image descriptions",
129 | subtitle:
130 | 'Adds the ability to describe images for the visually impaired.',
131 | vPadding: 15,
132 | showCheckBox: true,
133 | onPressed: () {
134 | openDarkModeSettings(context);
135 | },
136 | showDivider: false,
137 | ),
138 | HeaderWidget(
139 | 'Motion',
140 | secondHeader: true,
141 | ),
142 | SettingRowWidget(
143 | "Reduce Motion",
144 | subtitle:
145 | 'Limit the amount of in-app animations, including live engagement counts.',
146 | vPadding: 15,
147 | showCheckBox: true,
148 | onPressed: () {
149 | openDarkModeSettings(context);
150 | },
151 | ),
152 | SettingRowWidget(
153 | "Video autoplay",
154 | subtitle: 'Wi-Fi only ',
155 | onPressed: () {
156 | openDarkModeSettings(context);
157 | },
158 | ),
159 | ],
160 | ),
161 | );
162 | }
163 | }
164 |
--------------------------------------------------------------------------------