├── 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 | --------------------------------------------------------------------------------