diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..dd84ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..7c361dd --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: b041144f833e05cf463b8887fa12efdec9493488 + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..6b753b6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "meme_baaz", + "program": "lib/main.dart", + "request": "launch", + "type": "dart", + // "args": ["--no-sound-null-safety"] + } + ] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..57cfd3b --- /dev/null +++ b/README.md @@ -0,0 +1,104 @@ + +# MemeBaaz - Memes & Short Videos App + +Memebaaz is a video/images sharing app, Anyone can share short videos and images through app, the media will go through admin's approval. + + +## Demo + +[Install From Play Store (30K+ Downloads)](https://play.google.com/store/apps/details?id=com.memebaaz.MemeBaaz +) + + +## Screenshots + +![App Screenshot](https://user-images.githubusercontent.com/27288409/185353359-5df6113a-6c3a-4fbd-845e-58d52d42f0af.png) + + +## Features + +- Like/Download/Share button +- Infinite Scroll +- Google Ads +- Local Save +- Categorized Menu +- Responsive Design +- Inbuild Admin Page +- Everyone can upload +- Cache Video/Image +- Media Compression (When uploading) +- Double Tap Like Effect Like Instagram +- Pagination, etc + + + + + + +## Tech Stack + +**Client:** Flutter, Getx, Firebase SDK + +**Server:** Firebase, Cloud Firestore, Cloud Storage + + +## Run Locally + +Clone the project as you like + +```bash + gh repo clone rawquesh/memebaaz +``` + +Go to the project directory + +```bash + cd menebaaz +``` + +Install dependencies + +```bash + flutter pub get +``` + +## Connect firebase services + +This project is connected to Firebase Auth, Firestore, Storage, Messages, etc: + +- Create Firebase Project +- Add Android with Package Name: ```com.memebaaz.MemeBaaz```, App nickname: ```MemeBaaz``` +- Add Firebase to the Project as official documentation + +## Firestore Data Model + +You will need to create few Collection/Documents to start the app + +```json +{ + "config": { + "categories": { + "data": ["category 1", "category 2"] // categories + }, + "keys": { + "key": "12345" // Password for accessing admin page + } + }, + "content": [ + // Media Documents + ] +} + +``` +![image](https://media.discordapp.net/attachments/729341849495666699/1009739494112636939/Screenshot_2022-08-18_134646.png) + +## Authors + +- [@rawquesh](https://www.github.com/rawquesh) + + +## Feedback + +If you have any feedback, please reach out to us at [Twittter](https://twitter.com/rawquesh) + + diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..108d105 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1 @@ +include: package:pedantic/analysis_options.yaml diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..c13e188 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,11 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +/key.properties +/key.properties +/app/google-services.json +/app/key.jks +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..3e3ffb0 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,79 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} +apply plugin: 'com.google.gms.google-services' +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +def keystoreProperties = new Properties() +def keystorePropertiesFile = rootProject.file('key.properties') +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} + +android { + compileSdkVersion flutter.compileSdkVersion + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + applicationId "com.memebaaz.MemeBaaz" + minSdkVersion 21 + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + } + + + buildTypes { + release { + signingConfig signingConfigs.release + minifyEnabled true + shrinkResources true + } + } +} + +flutter { + source '../..' +} + +dependencies { + + implementation 'com.google.firebase:firebase-analytics:17.2.2' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..970c1c2 --- /dev/null +++ b/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..50a4dd8 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/example/LolluMemer/MainActivity.kt b/android/app/src/main/kotlin/com/example/LolluMemer/MainActivity.kt new file mode 100644 index 0000000..7f2d251 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/LolluMemer/MainActivity.kt @@ -0,0 +1,7 @@ +package com.memebaaz.MemeBaaz + +import io.flutter.embedding.android.FlutterActivity + + +class MainActivity: FlutterActivity() { +} diff --git a/android/app/src/main/res/colors.xml b/android/app/src/main/res/colors.xml new file mode 100644 index 0000000..4fb5390 --- /dev/null +++ b/android/app/src/main/res/colors.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/android/app/src/main/res/drawable-hdpi/splash.png b/android/app/src/main/res/drawable-hdpi/splash.png new file mode 100644 index 0000000..45ebfce Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-mdpi/splash.png b/android/app/src/main/res/drawable-mdpi/splash.png new file mode 100644 index 0000000..67ffdeb Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-v21/background.png b/android/app/src/main/res/drawable-v21/background.png new file mode 100644 index 0000000..e29b3b5 Binary files /dev/null and b/android/app/src/main/res/drawable-v21/background.png differ diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..3cc4948 --- /dev/null +++ b/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/android/app/src/main/res/drawable-xhdpi/splash.png b/android/app/src/main/res/drawable-xhdpi/splash.png new file mode 100644 index 0000000..0b9e53e Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/splash.png b/android/app/src/main/res/drawable-xxhdpi/splash.png new file mode 100644 index 0000000..aa15fb9 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/splash.png b/android/app/src/main/res/drawable-xxxhdpi/splash.png new file mode 100644 index 0000000..a172075 Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable/background.png b/android/app/src/main/res/drawable/background.png new file mode 100644 index 0000000..e29b3b5 Binary files /dev/null and b/android/app/src/main/res/drawable/background.png differ diff --git a/android/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..ca3826a --- /dev/null +++ b/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..3cc4948 --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..c4a603d --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..c4a603d --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..c2a3e4e Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..fdf1bee Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..7adcb34 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..d94365f Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..0441343 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..a4f047d Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..f5a63d7 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..2944c88 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..42c6d9b Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..a324e9e Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..4e0c949 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..6e223e0 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..259bc71 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..dd1f9eb Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..31b95ce Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/values-v31/styles.xml b/android/app/src/main/res/values-v31/styles.xml new file mode 100644 index 0000000..f5fdb6b --- /dev/null +++ b/android/app/src/main/res/values-v31/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..3748873 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..970c1c2 --- /dev/null +++ b/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..330ea7d --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,32 @@ +buildscript { + ext.kotlin_version = '1.6.10' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.google.gms:google-services:4.3.8' + classpath 'com.android.tools.build:gradle:7.1.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..3338982 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..fc4d8bf --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,29 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} \ No newline at end of file diff --git a/assets/404.svg b/assets/404.svg new file mode 100644 index 0000000..509060f --- /dev/null +++ b/assets/404.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/bg.jpg b/assets/bg.jpg new file mode 100644 index 0000000..295afa4 Binary files /dev/null and b/assets/bg.jpg differ diff --git a/assets/error.jpg b/assets/error.jpg new file mode 100644 index 0000000..7496da1 Binary files /dev/null and b/assets/error.jpg differ diff --git a/assets/instagram_like.flr b/assets/instagram_like.flr new file mode 100644 index 0000000..e5c92e5 Binary files /dev/null and b/assets/instagram_like.flr differ diff --git a/assets/new.jpg b/assets/new.jpg new file mode 100644 index 0000000..75bbfed Binary files /dev/null and b/assets/new.jpg differ diff --git a/assets/splash.png b/assets/splash.png new file mode 100644 index 0000000..d75dedb Binary files /dev/null and b/assets/splash.png differ diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..ec97fc6 --- /dev/null +++ b/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..c4855bf --- /dev/null +++ b/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..1e8c3c9 --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,41 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d335afb --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,503 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.LolluMemer; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.LolluMemer; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.LolluMemer; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..70693e4 --- /dev/null +++ b/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..fc2ce62 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..9f1db2a Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..a77fb4e Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..a1e806e Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..0bf7098 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..b410766 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..e469d8f Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..a77fb4e Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..16ab5b9 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..7ff48f0 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png new file mode 100644 index 0000000..4ba3426 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png new file mode 100644 index 0000000..6a23756 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png new file mode 100644 index 0000000..c06b5d6 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png new file mode 100644 index 0000000..ed580ff Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..7ff48f0 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..9f66c6c Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png new file mode 100644 index 0000000..e3343e4 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png new file mode 100644 index 0000000..642d5a0 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..05922f1 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..02f1399 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..cc7a24d Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json new file mode 100644 index 0000000..9f447e1 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "background.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png new file mode 100644 index 0000000..e29b3b5 Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..00cabce --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "LaunchImage.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "LaunchImage@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "LaunchImage@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..67ffdeb Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..0b9e53e Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..aa15fb9 Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..b169994 --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist new file mode 100644 index 0000000..436c2f9 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + LolluMemer + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + UIStatusBarHidden + + + diff --git a/ios/Runner/Runner-Bridging-Header.h b/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/lib/admin/content/buttons.dart b/lib/admin/content/buttons.dart new file mode 100644 index 0000000..9e45dec --- /dev/null +++ b/lib/admin/content/buttons.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/models/content.dart'; + +import 'controller.dart'; + +class ContentButtonsAdmin extends StatelessWidget { + final ContentModel content; + const ContentButtonsAdmin({Key? key, required this.content}) : super(key: key); + + @override + Widget build(BuildContext context) { + final c = Get.find(); + Expanded _makeItVerified() { + return Expanded( + child: OutlinedButton( + onPressed: () => c.changeStatus(content.id!, ContentStatus.verified), + child: Text('Make it verified', style: ptSansFont().copyWith(color: Colors.green.shade600, fontWeight: FontWeight.w500)), + ), + ); + } + + Expanded _putOnHold() { + return Expanded( + child: OutlinedButton( + onPressed: () => c.changeStatus(content.id!, ContentStatus.hold), + child: Text('Put on hold', style: ptSansFont().copyWith(color: Colors.red.shade600, fontWeight: FontWeight.w500)), + ), + ); + } + + return Row( + // crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (content.status == ContentStatus.verified) + _putOnHold() + else if (content.status == ContentStatus.pending) ...[ + _makeItVerified(), + sizedBoxW(10), + _putOnHold(), + ] else if (content.status == ContentStatus.hold) ...[ + _makeItVerified(), + sizedBoxW(10), + Expanded( + child: OutlinedButton( + onPressed: () => c.deleteDocForver(content.id!), + child: Text('Delete forver', style: ptSansFont().copyWith(color: Colors.red.shade800, fontWeight: FontWeight.w500)), + ), + ) + ], + ], + ); + } +} diff --git a/lib/admin/content/controller.dart b/lib/admin/content/controller.dart new file mode 100644 index 0000000..3dbbcb6 --- /dev/null +++ b/lib/admin/content/controller.dart @@ -0,0 +1,114 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:meme_baaz/models/content.dart'; + +class ContentPageAdminController extends GetxController { + RxList categories = ['verified', 'pending', 'hold'].obs; + RxList content = [].obs; + + RxString selectedCategory = 'verified'.obs; + + final Rx scrollController = ScrollController().obs; + + RxBool showFab = false.obs; + + RxBool ended = false.obs; + RxBool loading = false.obs; + + DocumentSnapshot? _lastDocumentSnapshot; + + static const int _limit = 15; + + Query get _query => FirebaseFirestore.instance.collection('content').orderBy('date_uploaded', descending: true).limit(_limit); + + Future fetchAllContent() async { + loading.value = true; + content.clear(); + late QuerySnapshot res; + final _content = []; + try { + res = await _query.where('status', isEqualTo: selectedCategory.value).get(); + + loading.value = true; + } on FirebaseException catch (e) { + print(e.message); + } + + loading.value = false; + res.docs.forEach((doc) => _content.add(ContentModel.fromSnapshot(doc))); + content.addAll(_content); + if (_content.length < _limit) { + ended.value = true; + } else { + _lastDocumentSnapshot = res.docs.last; + } + return; + } + + void fetchAllServicesLazy() async { + if (ended.value) return; + late QuerySnapshot res; + final _content = []; + try { + res = await _query.where('status', isEqualTo: selectedCategory.value).startAfterDocument(_lastDocumentSnapshot!).get(); + } on FirebaseException catch (e) { + print(e.message); + } + res.docs.forEach((doc) => _content.add(ContentModel.fromSnapshot(doc))); + content.addAll(_content); + if (_content.length < _limit) { + ended.value = true; + } else { + _lastDocumentSnapshot = res.docs.last; + } + } + + Future onRefresh() async { + _lastDocumentSnapshot = null; + ended.value = false; + await fetchAllContent(); + } + + void changeStatus(String uid, String status) { + content.removeWhere((e) => e.id == uid); + FirebaseFirestore.instance.collection('content').doc(uid).update({ + 'status': status, + 'date_uploaded': DateTime.now(), + }); + } + + void deleteDocForver(String uid) { + content.removeWhere((e) => e.id == uid); + FirebaseFirestore.instance.collection('content').doc(uid).delete(); + } + + void onCategoriesSelect(String v) { + if (loading.isTrue) return; + selectedCategory.value = v; + _lastDocumentSnapshot = null; + ended.value = false; + fetchAllContent(); + final cntrl = scrollController.value; + cntrl.jumpTo(cntrl.position.minScrollExtent); + } + + @override + void onInit() { + fetchAllContent(); + scrollController.value.addListener(() { + if (scrollController.value.position.pixels > 350) { + showFab.value = true; + } else { + showFab.value = false; + } + }); + super.onInit(); + } + + @override + void onClose() { + scrollController.value.dispose(); + super.onClose(); + } +} diff --git a/lib/admin/content/view.dart b/lib/admin/content/view.dart new file mode 100644 index 0000000..bded972 --- /dev/null +++ b/lib/admin/content/view.dart @@ -0,0 +1,181 @@ +import 'package:animations/animations.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:get/get.dart'; +import 'package:lazy_load_scrollview/lazy_load_scrollview.dart'; +import 'package:meme_baaz/admin/content/buttons.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/constant/theme.dart'; +import 'package:meme_baaz/screens/player/media.dart'; +import 'package:meme_baaz/screens/player/shimmers.dart'; +import 'package:meme_baaz/screens/player/title.dart'; +import 'package:meme_baaz/utils/scroll_to_top.dart'; +import 'package:timeago/timeago.dart' as timeago; + +import 'controller.dart'; + +class ContentPageAdmin extends StatelessWidget { + const ContentPageAdmin({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Obx(() { + final controller = Get.put(ContentPageAdminController()); + return Scaffold( + floatingActionButton: () { + final _size = myFontSize(50); + return SizedBox( + height: _size, + width: _size, + child: PageTransitionSwitcher( + duration: const Duration(milliseconds: 600), + transitionBuilder: (child, primaryAnimation, secondaryAnimation) { + return FadeThroughTransition( + fillColor: Colors.transparent, + animation: primaryAnimation, + secondaryAnimation: secondaryAnimation, + child: child, + ); + }, + child: controller.showFab.value + ? FloatingActionButton( + onPressed: () => scrollToTop(controller.scrollController.value), + child: Icon(Icons.arrow_upward, size: myFontSize(25)), + ) + : const SizedBox.shrink(), + ), + ); + }(), + body: LazyLoadScrollView( + onEndOfPage: controller.fetchAllServicesLazy, + isLoading: controller.loading.isTrue, + child: RefreshIndicator( + onRefresh: controller.onRefresh, + color: themeColor, + edgeOffset: 80, + child: CustomScrollView( + cacheExtent: screenHeight * 1.7, + controller: controller.scrollController.value, + slivers: [ + SliverAppBar( + pinned: true, + floating: true, + elevation: 0, + title: Text('Manage', style: ptSansFont(18).copyWith(letterSpacing: 1)), + bottom: PreferredSize( + preferredSize: Size(screenWidth, 40), + child: SizedBox( + height: 40, + child: () { + if (controller.categories.isEmpty) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: myFontSize(10)), + child: const TagsShimmer(), + ); + } + return Row( + children: [ + for (final cate in controller.categories) + Obx( + () => Padding( + padding: const EdgeInsets.symmetric(horizontal: 3), + child: RawChip( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: .1), + selectedColor: themeColor, + backgroundColor: Get.isDarkMode ? Colors.white10 : Colors.black12, + selected: cate == controller.selectedCategory.value, + showCheckmark: false, + onSelected: (b) { + if (b) controller.onCategoriesSelect(cate); + }, + label: Text( + cate.capitalize ?? '', + style: ptSansFont(13.5).copyWith( + color: cate == controller.selectedCategory.value ? Colors.white : Get.theme.colorScheme.secondary, + letterSpacing: 1.2, + ), + ), + ), + ), + ), + ], + ); + }(), + ), + ), + ), + SliverList( + delegate: SliverChildListDelegate( + [ + sizedBoxH(10), + if (controller.loading.isTrue) + const ContentShimmer() + else if (controller.content.isEmpty) + SizedBox( + height: screenHeight, + child: Column( + children: [ + const Spacer(flex: 40), + SvgPicture.asset('assets/404.svg', height: myFontSize(50), color: themeColor), + const SizedBox(height: 15), + Text('No memes were found.', style: ptSansFont()), + const Spacer(flex: 100), + ], + ), + ) + else + for (final content in controller.content) + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: EdgeInsets.all(myFontSize(13)), + child: Row( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(100), + child: Image.asset('assets/new.jpg', height: myFontSize(30), width: myFontSize(30)), + ), + sizedBoxW(10), + Text('MemeBaaz', style: ptSansFont(13).copyWith(letterSpacing: 1, fontWeight: FontWeight.bold)), + sizedBoxW(10), + Text(content.status!.capitalize!, style: ptSansFont(13).copyWith(letterSpacing: 1)), + const Spacer(), + Text(timeago.format(content.dateUploaded!).capitalizeFirst!, style: ptSansFont(11.5)), + ], + ), + ), + ContentMedia(content: content, key: Key(content.id!), like: false), + contentTitleWidget(content), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 5), + child: ContentButtonsAdmin(content: content), + ), + ], + ), + if (controller.content.isNotEmpty) + Container( + alignment: Alignment.center, + height: myFontSize(30) + 20, + child: controller.ended.value + ? const Text('No More Memes.') + : SizedBox( + height: myFontSize(20), + width: myFontSize(20), + child: const CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Colors.black), + ), + ), + ) + ], + ), + ), + ], + ), + ), + ), + ); + }); + } +} diff --git a/lib/admin/functions/key_field.dart b/lib/admin/functions/key_field.dart new file mode 100644 index 0000000..77d9c3b --- /dev/null +++ b/lib/admin/functions/key_field.dart @@ -0,0 +1,79 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:meme_baaz/admin/main/view.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/constant/theme.dart'; +import 'package:meme_baaz/functions/getSnack_bar.dart'; +import 'package:meme_baaz/functions/get_navigation.dart'; + +Future showKeyField(BuildContext context) async { + return showCupertinoDialog( + context: context, + barrierDismissible: true, + builder: (context) { + final ptSans2 = ptSansFont(); + var _value = ''; + + return AlertDialog( + content: FormBuilderTextField( + autovalidateMode: AutovalidateMode.onUserInteraction, + name: 'key_field', + onChanged: (v) => _value = v!, + initialValue: '', + style: ptSans2, + decoration: _decoration('Key'), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('Cancel', style: ptSansFont().copyWith(color: themeColor)), + ), + TextButton( + onPressed: () async { + try { + final res = await FirebaseFirestore.instance.collection('config').doc('keys').get(); + final _data = res.data()?['key'] as String; + if (_value == _data) { + Navigator.pop(context); + getNavigation(const AdminPage()); + } else { + await showToast(msg: 'incorrect key.'); + } + } on FirebaseException catch (e) { + await showToast(msg: e.message!); + } + }, + child: Text('Next', style: ptSansFont().copyWith(color: themeColor)), + ), + ], + ); + }, + ); +} + +InputDecoration _decoration([String? label]) { + const radius = BorderRadius.all(Radius.circular(5.0)); + // TextStyle _style = ptSans(39).copyWith(letterSpacing: 0.3); + return InputDecoration( + hintText: label, + hintStyle: ptSansFont(), + errorStyle: ptSansFont(), + // isCollapsed: true, + contentPadding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10.0), + fillColor: Colors.black, + border: const UnderlineInputBorder( + borderSide: BorderSide(color: Colors.black12, width: 2), + borderRadius: radius, + ), + enabledBorder: const UnderlineInputBorder( + borderSide: BorderSide(color: Colors.black12, width: 2), + borderRadius: radius, + ), + focusedBorder: const UnderlineInputBorder( + borderSide: BorderSide(color: themeColor, width: 2.0), + borderRadius: radius, + ), + ); +} diff --git a/lib/admin/main/view.dart b/lib/admin/main/view.dart new file mode 100644 index 0000000..8382bc9 --- /dev/null +++ b/lib/admin/main/view.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:line_icons/line_icons.dart'; +import 'package:meme_baaz/admin/content/view.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/constant/theme.dart'; +import 'package:meme_baaz/functions/get_navigation.dart'; + +class AdminPage extends StatelessWidget { + const AdminPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + elevation: 0, + title: Text('Admin Page', style: ptSansFont(18).copyWith(letterSpacing: 1)), + ), + body: ListView( + padding: EdgeInsets.all(myFontSize(5)), + children: [ + Row( + children: [ + _item(LineIcons.photoVideo, 'Content', const ContentPageAdmin()), + _item(LineIcons.alternateLevelUp, 'Coming Soon', null), + ], + ), + ], + ), + ); + } +} + +Widget _item(IconData icon, String text1, Widget? widget) { + return Expanded( + child: Container( + margin: EdgeInsets.all(myFontSize(5)), + decoration: BoxDecoration( + color: Get.theme.cardColor, + borderRadius: BorderRadius.circular(10), + ), + // decoration: buildDecoration(radius: 10, color: Colors.grey.withOpacity(.25)), + height: myFontSize(120), + child: Material( + type: MaterialType.transparency, + borderRadius: BorderRadius.circular(myFontSize(5)), + child: InkWell( + borderRadius: BorderRadius.circular(10), + onTap: () async { + if (widget == null) return; + await Future.delayed(const Duration(milliseconds: 100)); + getNavigation(widget); + }, + child: Column( + children: [ + const Spacer(flex: 100), + Icon( + icon, + size: myFontSize(25), + color: themeColor, + ), + const Spacer(flex: 30), + Text(text1, textAlign: TextAlign.center, style: ptSansFont(16).copyWith(color: themeColor)), + const Spacer(flex: 100), + ], + ), + ), + ), + ), + ); +} diff --git a/lib/ads/banner.dart b/lib/ads/banner.dart new file mode 100644 index 0000000..cbddc7a --- /dev/null +++ b/lib/ads/banner.dart @@ -0,0 +1,89 @@ +// import 'package:facebook_audience_network/facebook_audience_network.dart'; +import 'package:flutter/material.dart'; +// import 'package:meme_baaz/ads/const.dart'; +// import 'package:meme_baaz/constant/theme.dart'; +// import 'package:native_admob_flutter/native_admob_flutter.dart'; + +class BannerAdsView extends StatefulWidget { + const BannerAdsView({Key? key}) : super(key: key); + + @override + _BannerAdsViewState createState() => _BannerAdsViewState(); +} + +class _BannerAdsViewState extends State { + // final controller = NativeAdController(unitId: AdsService.native); + + @override + void initState() { + // controller.load(keywords: AdsService.adsRequest.keywords!, unitId: AdsService.native); + super.initState(); + } + + @override + void dispose() { + // controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + // const _height = 60.0; + // return NativeAd( + // controller: controller, + // unitId: AdsService.native, + // height: _height, + // builder: (context, child) { + // return Material(child: child); + // }, + // buildLayout: adBannerLayoutBuilder, // smallAdTemplateLayoutBuilder + // loading: const SizedBox( + // height: _height, + // child: Center(child: Text('showing advertisement here')), + // ), + // nonPersonalizedAds: false, + // error: const SizedBox( + // height: _height, + // child: Center(child: Text('unable to load Ad')), + // ), + // icon: AdImageView(padding: const EdgeInsets.only(left: 6)), + // headline: AdTextView(style: const TextStyle(color: Colors.black)), + // advertiser: AdTextView(style: const TextStyle(color: Colors.black)), + // body: AdTextView(style: const TextStyle(color: Colors.black), maxLines: 1), + // media: AdMediaView(height: _height, width: 140), + // button: AdButtonView( + // height: _height, + // decoration: AdDecoration(borderRadius: AdBorderRadius.all(5), backgroundColor: Colors.white), + // margin: const EdgeInsets.only(left: 6, right: 6), + // textStyle: const TextStyle(color: themeColor, fontSize: 14), + // elevation: 0, + // elevationColor: themeColor, + // pressColor: themeColor3, + // ), + // ); + return SizedBox.shrink(); + // return Container( + // alignment: Alignment(0.5, 1), + // child: FacebookBannerAd( + // placementId: '429732795171881_429734448505049', + // bannerSize: BannerSize.STANDARD, + // listener: (result, value) { + // switch (result) { + // case BannerAdResult.ERROR: + // print('Error: $value'); + // break; + // case BannerAdResult.LOADED: + // print('Loaded: $value'); + // break; + // case BannerAdResult.CLICKED: + // print('Clicked: $value'); + // break; + // case BannerAdResult.LOGGING_IMPRESSION: + // print('Logging Impression: $value'); + // break; + // } + // }, + // ), + // ); + } +} diff --git a/lib/ads/const.dart b/lib/ads/const.dart new file mode 100644 index 0000000..ab480a6 --- /dev/null +++ b/lib/ads/const.dart @@ -0,0 +1,31 @@ +// import 'package:google_mobile_ads/google_mobile_ads.dart'; + +mixin AdsService { + // static AdRequest adsRequest = const AdRequest( + // keywords: [ + // 'phones', + // 'memes', + // 'fun', + // 'top', + // 'instagram', + // 'tiktok', + // 'youtube', + // 'india', + // ], + // contentUrl: 'https://memes.com', + // nonPersonalizedAds: false, + // ); + + // static int maxBannerAds = 5; + + // static String get native => nativeId; + // static String get interstitial => interstitialId; + + // static const bannerId = 'ca-app-pub-3434189224560413/8408407556'; + // static const interstitialId = 'ca-app-pub-3434189224560413/6712182508'; + // static const nativeId = 'ca-app-pub-3434189224560413/1951175376'; + + // static const bannerTestId = 'ca-app-pub-3940256099942544/6300978111'; + // static const nativeTestId = 'ca-app-pub-3940256099942544/2247696110'; + // static const interstitialTestId = 'ca-app-pub-3940256099942544/1033173712'; +} diff --git a/lib/ads/interstitial.dart b/lib/ads/interstitial.dart new file mode 100644 index 0000000..2653d14 --- /dev/null +++ b/lib/ads/interstitial.dart @@ -0,0 +1,25 @@ +import 'dart:math'; + +// import 'package:meme_baaz/ads/const.dart'; +// import 'package:native_admob_flutter/native_admob_flutter.dart'; +// +// import 'package:facebook_audience_network/facebook_audience_network.dart'; + +Future showInterstitialAds([int max = 2]) async { + if (Random().nextInt(max) == 0) { + // final interstitialAd = InterstitialAd(unitId: AdsService.interstitial); + // await interstitialAd.load(force: true, keywords: AdsService.adsRequest.keywords!, unitId: AdsService.interstitial); + // if (interstitialAd.isAvailable) { + // await interstitialAd.show(); + // } + + // await FacebookAudienceNetwork.init(testingId: 'a77955ee-3304-4635-be65-81029b0f5201'); + + // await FacebookInterstitialAd.loadInterstitialAd( + // placementId: '429732795171881_429734561838371', + // listener: (result, value) { + // if (result == InterstitialAdResult.LOADED) FacebookInterstitialAd.showInterstitialAd(delay: 1000); + // }, + // ); + } +} diff --git a/lib/constant/keys.dart b/lib/constant/keys.dart new file mode 100644 index 0000000..aabd7a8 --- /dev/null +++ b/lib/constant/keys.dart @@ -0,0 +1,5 @@ +class StorageKeys { + static const String like = 'like'; + static const String save = 'save'; + static const String theme = 'theme'; +} diff --git a/lib/constant/style.dart b/lib/constant/style.dart new file mode 100644 index 0000000..3182083 --- /dev/null +++ b/lib/constant/style.dart @@ -0,0 +1,21 @@ +import 'package:flutter/cupertino.dart'; +import 'package:get/get.dart'; +import 'package:google_fonts/google_fonts.dart'; + +double myFontSize(double fontSize) => ((((fontSize / Get.width) + (fontSize / Get.height)) / 3) + (fontSize / 10)) * 10; + +double get screenHeight => Get.height; + +double get screenWidth => Get.width; + +// ignore: deprecated_member_use +TextStyle ptSansFont([double size = 15.1]) => GoogleFonts.ptSans(fontSize: myFontSize(size), letterSpacing: 0.2, color: Get.theme.accentColor); + +SizedBox sizedBoxH(double height) => SizedBox(height: (height * 500) / Get.height); + +SizedBox sizedBoxW(double width) => SizedBox(width: (width * 500) / Get.height); +// SizedBox sizedBoxP(double size) => SizedBox(width: myFontSize(size)); + +const noImageUrl = 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/ac/No_image_available.svg/600px-No_image_available.svg.png'; +const noImageUrlShop = 'https://storage.googleapis.com/possystem-db408.appspot.com/profile/Z3iIXX2GE9bApl4MNHiTKPKmgKG2/image_picker4696987569345710534.png'; +const hashString = 'UGMaCiysX#v0%1?bR*t8C6rX+wFGX9xuf5Rj'; diff --git a/lib/constant/theme.dart b/lib/constant/theme.dart new file mode 100644 index 0000000..05a9f33 --- /dev/null +++ b/lib/constant/theme.dart @@ -0,0 +1,27 @@ +// import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:meme_baaz/constant/style.dart'; + +final dartThemeData = ThemeData.dark().copyWith( + splashColor: Colors.transparent, + brightness: Brightness.dark, + hintColor: Colors.black, + // scaffoldBackgroundColor: Colors.black26, + iconTheme: IconThemeData(color: Colors.white, size: myFontSize(25)), colorScheme: ColorScheme.fromSwatch().copyWith(secondary: Colors.white), +); +final lightThemeData = ThemeData.light().copyWith( + scaffoldBackgroundColor: Colors.white, + canvasColor: const Color(0xFFD0FFFF), + hintColor: Colors.black, + iconTheme: IconThemeData(color: Colors.black, size: myFontSize(25)), + appBarTheme: const AppBarTheme( + color: Colors.white, + iconTheme: IconThemeData(color: Colors.black12), + ), colorScheme: ColorScheme.fromSwatch().copyWith(secondary: Colors.black87), +); + +const themeColor = Color(0xff3D79F4); + +const Color themeColor3 = Color(0xFF09126C); + +const myLinearGradient = LinearGradient(colors: [themeColor, themeColor3]); diff --git a/lib/database/database.dart b/lib/database/database.dart new file mode 100644 index 0000000..51a4994 --- /dev/null +++ b/lib/database/database.dart @@ -0,0 +1,6 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; + +class Database { + static Future addLike(String id, bool increment) async => + FirebaseFirestore.instance.collection('content').doc(id).update({'likes': FieldValue.increment(increment ? 1 : -1)}); +} diff --git a/lib/functions/dialog.dart b/lib/functions/dialog.dart new file mode 100644 index 0000000..0805b74 --- /dev/null +++ b/lib/functions/dialog.dart @@ -0,0 +1,51 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:meme_baaz/constant/style.dart'; +// import 'package:flutter/services.dart' show SystemNavigator; + +Future myDialog({ + required BuildContext context, + String title = 'title', + String content = 'Content', + String yes = 'Yes', + String no = 'No', + void Function()? onTap, + void Function()? noTap, +}) async { + final style = ptSansFont(); + return showCupertinoDialog( + barrierDismissible: true, + context: context, + builder: (context) { + final borderRadius = BorderRadius.circular(3); + final borderRadius2 = BorderRadius.circular(10); + final black26 = Colors.black26; + return AlertDialog( + shape: RoundedRectangleBorder(borderRadius: borderRadius2), + title: Text(title.toUpperCase(), style: style), + content: Text(content, style: style), + actions: [ + InkWell( + borderRadius: borderRadius, + splashColor: black26, + onTap: noTap ?? () => Navigator.of(context).pop(), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 13, vertical: 8), + child: Text(no.toUpperCase(), style: style), + ), + ), + // SizedBox(height: 16), + InkWell( + splashColor: black26, + borderRadius: borderRadius, + onTap: onTap, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 13, vertical: 8), + child: Text(yes.toUpperCase(), style: style), + ), + ), + ], + ); + }, + ); +} diff --git a/lib/functions/getSnack_bar.dart b/lib/functions/getSnack_bar.dart new file mode 100644 index 0000000..8e30380 --- /dev/null +++ b/lib/functions/getSnack_bar.dart @@ -0,0 +1,47 @@ +// import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:get/get.dart'; + +import '../constant/style.dart'; +import '../constant/theme.dart'; + +Future showToast({required String msg, bool short = true}) async { + await Fluttertoast.cancel(); + await Fluttertoast.showToast( + msg: msg, + toastLength: short ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG, + gravity: ToastGravity.BOTTOM, + backgroundColor: Colors.red, + textColor: Colors.white, + fontSize: 16.0, + ); +} + +void getSnackLoader([String msg = 'Please wait!']) { + if (Get.isSnackbarOpen) { + Get.back(); + } + Get.snackbar( + 'Loading', + msg, + titleText: Text('Loading', style: ptSansFont().copyWith(fontWeight: FontWeight.bold, color: themeColor3)), + messageText: Text(msg, style: ptSansFont().copyWith(color: themeColor3)), + margin: EdgeInsets.all(10), + colorText: Colors.blue[900], + forwardAnimationCurve: Curves.fastLinearToSlowEaseIn, + reverseAnimationCurve: Curves.fastLinearToSlowEaseIn, + duration: const Duration(minutes: 5), + isDismissible: false, + backgroundGradient: myLinearGradient, + // borderRadius: 4, + // icon: Padding( + // padding: const EdgeInsets.only(left: 20,right: 10), + // child: CupertinoActivityIndicator(radius: 10), + // ), + overlayBlur: 2, + barBlur: 15, + + snackPosition: SnackPosition.BOTTOM, + ); +} diff --git a/lib/functions/get_navigation.dart b/lib/functions/get_navigation.dart new file mode 100644 index 0000000..874f19b --- /dev/null +++ b/lib/functions/get_navigation.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart' show Route, Widget; +import 'package:get/get.dart'; + +void getNavigation(Widget widget) { + Get.to( + widget, + transition: Transition.cupertino, + duration: const Duration(milliseconds: 450), + popGesture: true, + preventDuplicates: false, + ); +} + +// void getNavigationwithoutanim(Widget widget) { +// Get.to( +// () => widget, +// transition: Transition.fadeIn, +// duration: Duration(milliseconds: 500), +// popGesture: true, +// fullscreenDialog: true, +// ); +// } + +void getNavigation2(Widget widget) { + Get.offAll( + () => widget, + popGesture: true, + predicate: (Route route) => false, + transition: Transition.cupertino, + duration: const Duration(milliseconds: 500), + ); +} diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..c029f04 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,57 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; +import 'package:meme_baaz/constant/theme.dart'; +import 'package:meme_baaz/screens/nav_bar/view.dart'; + +import 'constant/keys.dart'; + +Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + + await Firebase.initializeApp(); + await GetStorage.init(); + manageStorage(); + await FirebaseAuth.instance.signInAnonymously(); + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return GetMaterialApp( + enableLog: false, + debugShowCheckedModeBanner: false, + title: 'Meme baaz', + darkTheme: dartThemeData, + themeMode: _setTheme(), + theme: lightThemeData, + home: MyNavBar(), + ); + } +} + +ThemeMode _setTheme() { + final box = GetStorage(); + final v = box.read(StorageKeys.theme); + if (v!) { + return ThemeMode.dark; + } else { + return ThemeMode.light; + } +} + +void manageStorage() { + final box = GetStorage(); + if (box.read(StorageKeys.like) == null) { + box.write(StorageKeys.like, ['0']); + } + if (box.read(StorageKeys.save) == null) { + box.write(StorageKeys.save, ['0']); + } + if (box.read(StorageKeys.theme) == null) { + box.write(StorageKeys.theme, false); + } +} diff --git a/lib/models/content.dart b/lib/models/content.dart new file mode 100644 index 0000000..9ea6f1f --- /dev/null +++ b/lib/models/content.dart @@ -0,0 +1,66 @@ +import 'dart:math'; + +import 'package:cloud_firestore/cloud_firestore.dart' show DocumentSnapshot, Timestamp; +// import 'package:meme_baaz/ads/const.dart'; + +class ContentModel { + String? id; + DateTime? dateUploaded; + String? title; + String? type; + String? url; + String? status; + List? tags; + int? likes; + int? random; + double? size; + double? aspectRatio; + + ContentModel({ + this.id, + this.dateUploaded, + this.title, + this.type, + this.url, + this.status, + this.tags, + this.likes, + this.size, + this.random, + this.aspectRatio, + }); + + ContentModel.fromSnapshot(DocumentSnapshot doc) { + id = doc.id; + dateUploaded = (doc['date_uploaded'] as Timestamp).toDate(); + title = doc['title']; + type = doc['type']; + url = doc['url']; + status = doc['status']; + tags = doc['tags'].cast(); + likes = doc['likes']; + size = doc['size']; + aspectRatio = doc['aspect_ratio']; + random = Random().nextInt(0); + } + + Map toJson() { + final data = {}; + data['date_uploaded'] = dateUploaded; + data['title'] = title; + data['type'] = type; + data['url'] = url; + data['status'] = status; + data['tags'] = tags; + data['likes'] = likes; + data['size'] = size; + data['aspect_ratio'] = aspectRatio; + return data; + } +} + +mixin ContentStatus { + static String verified = 'verified'; + static String hold = 'hold'; + static String pending = 'pending'; +} diff --git a/lib/models/content.json b/lib/models/content.json new file mode 100644 index 0000000..791bcfe --- /dev/null +++ b/lib/models/content.json @@ -0,0 +1,16 @@ +{ + "date_uploaded": "", + "uploder_name": "", + "uploader_id": "", + "height": 100, + "width": 100, + "type": "image", + "url": "", + "status": "approved", + "tags": ["non-veg"], + "likes": 0, + "shares": 0, + "favorites": 0, + "downloads": 0, + "size": 0 +} diff --git a/lib/models/upload.dart b/lib/models/upload.dart new file mode 100644 index 0000000..38a66ed --- /dev/null +++ b/lib/models/upload.dart @@ -0,0 +1,88 @@ +// import 'dart:typed_data'; + +// import 'package:wechat_assets_picker/wechat_assets_picker.dart' show AssetEntity; + +// class AssetEntityModel { +// final AssetEntity? assetEntity; +// final String? id; +// final String title; +// final String? url; +// final UploadingStatus status; +// // final Uint8List? imageData; +// // final File? videoData; + +// AssetEntityModel({ +// this.assetEntity, +// this.id, +// this.title = "", +// this.url, +// this.status = UploadingStatus.loaded, +// // this.imageData, +// // this.videoData, +// }); + +// AssetEntityModel copyWith({ +// AssetEntity? assetEntity, +// String? id, +// String? title, +// String? url, +// UploadingStatus? status, +// Uint8List? imageData, +// // File? videoData, +// }) { +// return AssetEntityModel( +// assetEntity: assetEntity ?? this.assetEntity, +// id: id ?? this.id, +// title: title ?? this.title, +// url: url ?? this.url, +// // imageData: imageData ?? this.imageData, +// status: status ?? this.status, +// // videoData: videoData ?? this.videoData, +// ); +// } +// } + +enum UploadingStatus { loaded, compressing, uploading, ready, error } + +String getUploadingStatus(UploadingStatus uploadingStatus) { + switch (uploadingStatus) { + case UploadingStatus.loaded: + return 'Loaded'; + case UploadingStatus.compressing: + return 'Compressing'; + case UploadingStatus.uploading: + return 'Uploading'; + case UploadingStatus.error: + return 'Error'; + case UploadingStatus.ready: + return 'Ready'; + default: + return 'failed'; + } +} + +class UploadingData { + final String id; + final String? url; + final String title; + final List tags; + final UploadingStatus uploadingStatus; + + UploadingData({required this.id, this.url, this.uploadingStatus = UploadingStatus.loaded, this.title = '', this.tags = const []}); + + UploadingData copyWith({ + String? id, + String? url, + String? title, + List? tags, + UploadingStatus? uploadingStatus, + }) { + return UploadingData( + id: id ?? this.id, + title: title ?? this.title, + uploadingStatus: uploadingStatus ?? this.uploadingStatus, + url: url ?? this.url, + tags: tags ?? this.tags, + ); + } +} diff --git a/lib/package/shimmer.dart b/lib/package/shimmer.dart new file mode 100644 index 0000000..0bb1d3a --- /dev/null +++ b/lib/package/shimmer.dart @@ -0,0 +1,120 @@ +import 'package:flutter/material.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/constant/theme.dart'; +import 'package:shimmer/shimmer.dart'; +import 'package:get/get.dart' show GetPlatform; + +class MyShimmer extends StatelessWidget { + final bool showCart; + + const MyShimmer({Key? key, this.showCart = true}) : super(key: key); + @override + Widget build(BuildContext context) { + return Scaffold( + body: () { + if (GetPlatform.isWeb) { + return const SizedBox.expand( + child: Center( + child: CircularProgressIndicator( + backgroundColor: themeColor, + ), + ), + ); + } + return Column( + children: [ + const LinearProgressIndicator( + backgroundColor: themeColor, + valueColor: AlwaysStoppedAnimation(Color(0xffFFA3D9)), + ), + Expanded( + child: Container( + padding: const EdgeInsets.all(6.0), + child: Shimmer.fromColors( + baseColor: Colors.grey[300]!, + highlightColor: Colors.grey[100]!, + child: Column( + children: [ + Container( + margin: const EdgeInsets.all(5), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(2), + ), + height: 30, + ), + const SizedBox(height: 5), + ...List.generate( + 3, + (_) => Expanded( + child: Padding( + padding: const EdgeInsets.only(bottom: 10.0), + child: Row( + // crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Row( + children: [ + _newMethod(context), + const SizedBox(width: 10), + _newMethod(context), + ], + ), + ), + ], + ), + ), + ), + ), + // SizedBox(height: 5), + // Container(color: Colors.white, height: 35), + ], + ), + ), + ), + ), + ], + ); + }()); + } + + Widget _newMethod(BuildContext context) { + Widget container() => Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(2), + ), + height: 10, + ); + + return Expanded( + child: Padding( + padding: const EdgeInsets.all(5.0), + child: Column( + // crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: container(), + ), + // SizedBox(height: 4), + // container(), + const SizedBox(height: 4), + Align( + alignment: Alignment.bottomRight, + child: Container( + width: screenWidth / 4, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(2), + ), + height: 10, + ), + ), + const SizedBox(height: 4), + container(), + ], + ), + ), + ); + } +} diff --git a/lib/screens/aboutUs/faq.dart b/lib/screens/aboutUs/faq.dart new file mode 100644 index 0000000..32a813a --- /dev/null +++ b/lib/screens/aboutUs/faq.dart @@ -0,0 +1,66 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/constant/theme.dart'; + +void showFAQs(BuildContext context) { + showCupertinoDialog( + context: context, + barrierDismissible: true, + builder: (context) { + final ptSans2 = ptSansFont(14.2); + final title = (String t) => Text(t, style: ptSans2.copyWith(color: Get.theme.colorScheme.secondary, fontWeight: FontWeight.w600)); + final detail = (String t) => Text(t, style: ptSansFont().copyWith(color: Get.theme.colorScheme.secondary.withOpacity(.6))); + var sizedBoxH2 = sizedBoxH(25); + return AlertDialog( + title: Text("FAQ's Page", style: ptSans2.copyWith(fontWeight: FontWeight.bold)), + scrollable: true, + content: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + title('Why MemeBaaz...?'), + detail( + "Because we provide better content and always fresh and new with great UI design and smooth interface also we pick memes and funny stuff from all over the internet and social media so you'll get as you want just from one app 😍.", + ), + sizedBoxH2, + sizedBoxH2, + title('Need improvement or facing issue...?'), + detail( + 'We are trying to improve thing but we need your feedback so please if you need new features or improvements then go to the play store and give us feedback 🙏.', + ), + sizedBoxH2, + sizedBoxH2, + title('Why advertisement...?'), + detail( + 'We need funds to pay for server maintenance and need to keep the application alive 😥.', + ), + sizedBoxH2, + sizedBoxH2, + title('New content updates?'), + detail( + 'We keep updating our content every 2,3 hour if all things are working and if some trouble comes then maybe it can take 1 day but not more than that and anyone can upload memes so you will always see fresh content 😉.', + ), + sizedBoxH2, + sizedBoxH2, + title('Disclaimer'), + detail( + 'All the images and assets provided in this app are taken from all over the internet and the owner of this app does not hold any rights so feel free to contact us for removing any material.', + ), + sizedBoxH2, + sizedBoxH2, + title('Email.'), + detail('bluetouchdev@gmail.com'), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('OK', style: ptSans2.copyWith(color: themeColor)), + ), + ], + ); + }, + ); +} diff --git a/lib/screens/aboutUs/view.dart b/lib/screens/aboutUs/view.dart new file mode 100644 index 0000000..55defa6 --- /dev/null +++ b/lib/screens/aboutUs/view.dart @@ -0,0 +1,171 @@ +// import 'package:pos_system/admin/main/view.dart'; +import 'package:get_storage/get_storage.dart'; +import 'package:line_icons/line_icons.dart'; +import 'package:meme_baaz/admin/functions/key_field.dart'; +import 'package:meme_baaz/constant/keys.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/constant/theme.dart'; +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart' show FontAwesomeIcons; +import 'package:meme_baaz/functions/getSnack_bar.dart'; +import 'package:meme_baaz/screens/aboutUs/faq.dart'; +// import 'package:meme_baaz/screens/bookmark/view.dart'; +// import 'package:meme_baaz/screens/upload/view.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:get/get.dart'; +import 'package:wc_flutter_share/wc_flutter_share.dart'; + +class AboutPage extends StatefulWidget { + const AboutPage({ + Key? key, + }) : super(key: key); + + @override + _AboutPageState createState() => _AboutPageState(); +} + +class _AboutPageState extends State { + final box = GetStorage(); + + bool isDark = false; + + @override + void initState() { + isDark = box.read(StorageKeys.theme) ?? false; + super.initState(); + } + + @override + Widget build(BuildContext context) { + final ptSansFont2 = ptSansFont(); + return Scaffold( + body: ListView( + padding: EdgeInsets.zero, + children: [ + () { + final imageSize = myFontSize(73); + return Stack( + // alignment: Alignment.center, + children: [ + Container( + // padding: EdgeInsets.only(top: Get.mediaQuery.padding.top), + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/bg.jpg'), + fit: BoxFit.cover, + ), + // gradient: myLinearGradient, + ), + height: myFontSize(110 + myFontSize(40) + Get.mediaQuery.padding.top), + child: Opacity( + opacity: 0.5, + child: Container( + padding: EdgeInsets.only(top: Get.mediaQuery.padding.top), + decoration: const BoxDecoration(gradient: myLinearGradient), + ), + ), + ), + Positioned( + right: 0, + top: Get.mediaQuery.padding.top, + child: ClipRRect( + borderRadius: BorderRadius.circular(100), + child: Material( + type: MaterialType.transparency, + child: IconButton( + color: themeColor3, + onPressed: () => showKeyField(context), + icon: const Icon(LineIcons.appStore), + ), + ), + ), + ), + Container( + padding: EdgeInsets.only(top: Get.mediaQuery.padding.top + myFontSize(10), left: myFontSize(19)), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(100), + child: Container( + color: themeColor.withOpacity(.2), + padding: const EdgeInsets.all(3), + child: ClipRRect( + borderRadius: BorderRadius.circular(100), + child: Image.asset('assets/new.jpg', height: imageSize, width: imageSize), + ), + ), + ), + ], + ), + sizedBoxH(7), + Text('Memebaazz', style: ptSansFont().copyWith(color: Colors.white, letterSpacing: 1)), + ], + ), + ), + ], + ); + }(), + sizedBoxH(20), + ListTile( + leading: Icon(LineIcons.sunAlt, color: Get.theme.colorScheme.secondary), + title: Text('Dark Mode', style: ptSansFont2), + trailing: Switch( + value: isDark, + onChanged: (v) { + isDark = v; + setState(() {}); + box.write(StorageKeys.theme, v); + showToast(msg: 'Please re-launch the app'); + }, + ), + ), + sizedBoxH(20), + ListTile( + leading: Icon(LineIcons.questionCircle, color: Get.theme.colorScheme.secondary), + onTap: () => showFAQs(context), + title: Text("FAQ's", style: ptSansFont2), + ), + ListTile( + leading: Icon(LineIcons.googlePlay, color: Get.theme.colorScheme.secondary), + onTap: () async { + const url = 'https://play.google.com/store/apps/details?id=com.memebaaz.MemeBaaz'; + if (await canLaunch(url)) { + await launch(url); + } else { + throw 'Could not launch $url'; + } + }, + title: Text('Rate the app', style: ptSansFont2), + ), + ListTile( + leading: Icon(Icons.share_outlined, color: Get.theme.colorScheme.secondary), + onTap: () { + WcFlutterShare.share( + sharePopupTitle: 'Share', + subject: 'MemeBaaz', + text: 'MemeBaaz is great app for daily new Memes and Short Vidoes, Download now : https://memebaaz.page.link/share', + mimeType: 'text/plain', + ); + }, + title: Text('Share', style: ptSansFont2), + ), + ListTile( + leading: const Icon(FontAwesomeIcons.instagram, color: Color(0xFFe4405f)), + onTap: () async { + const url = 'https://www.instagram.com/rawquesh/'; + if (await canLaunch(url)) { + await launch(url); + } else { + throw 'Could not launch $url'; + } + }, + title: Text('Follow on instagram', style: ptSansFont2), + ), + ], + ), + ); + } +} diff --git a/lib/screens/bookmark/controller.dart b/lib/screens/bookmark/controller.dart new file mode 100644 index 0000000..bd9c97a --- /dev/null +++ b/lib/screens/bookmark/controller.dart @@ -0,0 +1,36 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; +import 'package:meme_baaz/constant/keys.dart'; +import 'package:meme_baaz/models/content.dart'; + +class BookmarkController extends GetxController { + RxList content = [].obs; + RxBool isLoading = false.obs; + + Future fetchAllContent() async { + final box = GetStorage(); + final saveIds = box.read(StorageKeys.save); + isLoading.value = true; + content.clear(); + try { + final res = await FirebaseFirestore.instance + .collection('content') + .where(FieldPath.documentId, whereIn: saveIds) + // .orderBy('date_uploaded', descending: true) + .where('status', isEqualTo: ContentStatus.verified) + .get(); + res.docs.forEach((doc) => content.add(ContentModel.fromSnapshot(doc))); + } on FirebaseException catch (e) { + print(e.message); + } + isLoading.value = false; + return; + } + + @override + void onInit() { + fetchAllContent(); + super.onInit(); + } +} diff --git a/lib/screens/bookmark/view.dart b/lib/screens/bookmark/view.dart new file mode 100644 index 0000000..5476f18 --- /dev/null +++ b/lib/screens/bookmark/view.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get/get.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/constant/theme.dart'; +import 'package:meme_baaz/screens/player/icons.dart'; +import 'package:meme_baaz/screens/player/shimmers.dart'; +import 'package:meme_baaz/screens/player/media.dart'; +import 'package:meme_baaz/screens/player/title.dart'; +import 'package:timeago/timeago.dart' as timeago; + +import 'controller.dart'; + +class Bookmarks extends StatelessWidget { + const Bookmarks({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Obx(() { + final controller = Get.put(BookmarkController()); + return Scaffold( + appBar: AppBar( + elevation: 0, + title: Text('Saved', style: ptSansFont(18).copyWith(letterSpacing: 1)), + ), + body: RefreshIndicator( + onRefresh: controller.fetchAllContent, + color: themeColor, + child: ListView( + cacheExtent: 2000, + children: [ + sizedBoxH(10), + if (controller.isLoading.isTrue) + const ContentShimmer() + else if (controller.content.isEmpty) + SizedBox( + height: screenHeight / 1.5, + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgPicture.asset('assets/404.svg', height: myFontSize(50), color: themeColor), + const SizedBox(height: 15), + Text('No memes were found.', style: ptSansFont()), + const SizedBox(height: 20), + ], + ), + ), + ) + else + for (final content in controller.content) + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: EdgeInsets.all(myFontSize(13)), + child: Row( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(100), + child: Image.asset( + 'assets/new.jpg', + height: myFontSize(30), + width: myFontSize(30), + ), + ), + sizedBoxW(10), + Text('MemeBaaz', style: ptSansFont(13).copyWith(letterSpacing: 1, fontWeight: FontWeight.bold)), + const Spacer(), + Text(timeago.format(content.dateUploaded!).capitalizeFirst!, style: ptSansFont(11.5)), + ], + ), + ), + ContentMedia(content: content, key: Key(content.id!)), + contentTitleWidget(content), + ContentIcons(contentModel: content), + ], + ), + sizedBoxH(100), + ], + ), + ), + ); + }); + } +} diff --git a/lib/screens/home/controller.dart b/lib/screens/home/controller.dart new file mode 100644 index 0000000..ef19d91 --- /dev/null +++ b/lib/screens/home/controller.dart @@ -0,0 +1,127 @@ +import 'dart:async'; + +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:get/get.dart'; +import 'package:meme_baaz/ads/interstitial.dart'; +import 'package:meme_baaz/functions/getSnack_bar.dart'; +import 'package:meme_baaz/models/content.dart'; +import 'package:meme_baaz/screens/nav_bar/controller.dart'; + +class HomeController extends GetxController { + RxList categories = [].obs; + RxList content = [].obs; + + RxString selectedCategory = 'recent'.obs; + RxBool ended = false.obs; + RxBool loading = false.obs; + + DocumentSnapshot? _lastDocumentSnapshot; + + static const int _limit = 15; + + Future onRefresh() async { + _lastDocumentSnapshot = null; + ended.value = false; + await fetchAllContent(); + } + + Query get _query => FirebaseFirestore.instance + .collection('content') + .orderBy('date_uploaded', descending: true) + .where('status', isEqualTo: ContentStatus.verified) + .limit(_limit); + + Future fetchAllContent() async { + loading.value = true; + content.clear(); + late QuerySnapshot res; + final _content = []; + try { + if ('recent' == selectedCategory.value) { + res = await _query.get(); + } else if ('popular' == selectedCategory.value) { + Query query = FirebaseFirestore.instance + .collection('content') + .orderBy('likes', descending: true) + .where('status', isEqualTo: ContentStatus.verified) + .limit(_limit); + res = await query.get(); + } else { + res = await _query.where('tags', arrayContains: selectedCategory.value).get(); + } + loading.value = true; + } on FirebaseException catch (e) { + await showToast(msg: e.message!); + } + + loading.value = false; + res.docs.forEach((doc) => _content.add(ContentModel.fromSnapshot(doc))); + content.addAll(_content); + if (_content.length < _limit) { + ended.value = true; + } else { + _lastDocumentSnapshot = res.docs.last; + } + return; + } + + Future fetchAllContentLazy() async { + Timer(3.seconds, () => showInterstitialAds(1)); + if (ended.value) return; + late QuerySnapshot res; + final _content = []; + try { + if (selectedCategory.value == 'recent') { + res = await _query.startAfterDocument(_lastDocumentSnapshot!).get(); + } else if ('popular' == selectedCategory.value) { + Query query = FirebaseFirestore.instance + .collection('content') + .orderBy('likes', descending: true) + .where('status', isEqualTo: ContentStatus.verified) + .startAfterDocument(_lastDocumentSnapshot!) + .limit(_limit); + res = await query.get(); + } else { + res = await _query.where('tags', arrayContains: selectedCategory.value).startAfterDocument(_lastDocumentSnapshot!).get(); + } + } on FirebaseException catch (e) { + print(e.message); + } + res.docs.forEach((doc) => _content.add(ContentModel.fromSnapshot(doc))); + content.addAll(_content); + if (_content.length < _limit) { + ended.value = true; + } else { + _lastDocumentSnapshot = res.docs.last; + } + } + + Future fetchCategories() async { + try { + final res = await FirebaseFirestore.instance.collection('config').doc('categories').get(); + final _data = (res.data()?['data']).cast(); + _data.insertAll(0, ['recent', 'popular']); + categories.assignAll(_data); + } on FirebaseException catch (e) { + await showToast(msg: e.message!); + } + } + + void onCategoriesSelect(String v) { + if (loading.isTrue) return; + selectedCategory.value = v; + showInterstitialAds(5); + _lastDocumentSnapshot = null; + ended.value = false; + fetchAllContent(); + var cntrl = Get.find().scrollController.value; + cntrl.jumpTo(cntrl.position.minScrollExtent); + } + + @override + void onInit() { + fetchCategories(); + fetchAllContent(); + super.onInit(); + } +} diff --git a/lib/screens/home/view.dart b/lib/screens/home/view.dart new file mode 100644 index 0000000..f3da1f0 --- /dev/null +++ b/lib/screens/home/view.dart @@ -0,0 +1,193 @@ +import 'package:animations/animations.dart'; +import 'package:flutter/material.dart'; +// import 'package:flutter/rendering.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get/get.dart'; +import 'package:lazy_load_scrollview/lazy_load_scrollview.dart'; +import 'package:meme_baaz/ads/banner.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/constant/theme.dart'; +import 'package:meme_baaz/screens/player/icons.dart'; + +import 'package:meme_baaz/screens/player/shimmers.dart'; +import 'package:meme_baaz/screens/nav_bar/controller.dart'; +import 'package:meme_baaz/screens/player/media.dart'; +import 'package:meme_baaz/screens/player/title.dart'; +import 'package:meme_baaz/utils/scroll_to_top.dart'; +import 'package:timeago/timeago.dart' as timeago; + +import 'controller.dart'; + +class HomePage extends StatelessWidget { + const HomePage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Obx( + () { + final controller = Get.put(HomeController()); + final nController = Get.find(); + return Scaffold( + floatingActionButton: () { + final _size = myFontSize(50); + return SizedBox( + height: _size, + width: _size, + child: PageTransitionSwitcher( + duration: const Duration(milliseconds: 600), + transitionBuilder: (child, primaryAnimation, secondaryAnimation) { + return FadeThroughTransition( + fillColor: Colors.transparent, + animation: primaryAnimation, + secondaryAnimation: secondaryAnimation, + child: child, + ); + }, + child: nController.showFab.value + ? FloatingActionButton( + onPressed: () => scrollToTop(nController.scrollController.value), + child: Icon(Icons.arrow_upward, size: myFontSize(25)), + ) + : const SizedBox.shrink(), + ), + ); + }(), + body: LazyLoadScrollView( + onEndOfPage: controller.fetchAllContentLazy, + isLoading: controller.loading.isTrue, + child: RefreshIndicator( + onRefresh: controller.onRefresh, + color: themeColor, + edgeOffset: 80, + child: CustomScrollView( + cacheExtent: screenHeight * 2.6, + controller: nController.scrollController.value, + slivers: [ + SliverAppBar( + pinned: true, + floating: true, + elevation: 0, + title: Text('MemeBaaz', style: ptSansFont(18).copyWith(letterSpacing: 1)), + bottom: PreferredSize( + preferredSize: Size(screenWidth, 40), + child: SizedBox( + height: 40, + child: () { + if (controller.categories.isEmpty) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: myFontSize(10)), + child: const TagsShimmer(), + ); + } + return ListView( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + children: [ + for (final cate in controller.categories) + Obx( + () => Padding( + padding: const EdgeInsets.symmetric(horizontal: 3), + child: RawChip( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: .1), + selectedColor: themeColor, + backgroundColor: Get.isDarkMode ? Colors.white10 : Colors.black12, + selected: cate == controller.selectedCategory.value, + showCheckmark: false, + onSelected: (b) { + if (b) controller.onCategoriesSelect(cate); + }, + label: Text( + cate.capitalize ?? '', + style: ptSansFont(13.5).copyWith( + color: cate == controller.selectedCategory.value ? Colors.white : Get.theme.colorScheme.secondary, + letterSpacing: 1.2, + ), + ), + ), + ), + ), + ], + ); + }(), + ), + ), + ), + SliverList( + delegate: SliverChildListDelegate( + [ + sizedBoxH(10), + if (controller.loading.isTrue) + const ContentShimmer() + else if (controller.content.isEmpty) + SizedBox( + height: screenHeight / 1.5, + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgPicture.asset('assets/404.svg', height: myFontSize(50), color: themeColor), + const SizedBox(height: 15), + Text('No memes were found.', style: ptSansFont()), + const SizedBox(height: 20), + ], + ), + ), + ) + else + for (final content in controller.content) + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: EdgeInsets.all(myFontSize(13)), + child: Row( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(100), + child: Image.asset( + 'assets/new.jpg', + height: myFontSize(30), + width: myFontSize(30), + ), + ), + sizedBoxW(10), + Text('MemeBaaz', style: ptSansFont(13).copyWith(letterSpacing: 1, fontWeight: FontWeight.bold)), + const Spacer(), + Text(timeago.format(content.dateUploaded!).capitalizeFirst!, style: ptSansFont(11.5)), + ], + ), + ), + ContentMedia(content: content, key: Key(content.id!)), + contentTitleWidget(content), + ContentIcons(contentModel: content), + if (content.random == 0) BannerAdsView(), + ], + ), + if (controller.content.isNotEmpty) + Container( + alignment: Alignment.center, + height: myFontSize(30) + 20, + child: controller.ended.value + ? const Text('No More Memes.') + : SizedBox( + height: myFontSize(20), + width: myFontSize(20), + child: const CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Colors.black), + ), + ), + ) + ], + addAutomaticKeepAlives: false, + ), + ), + ], + ), + ), + ), + ); + }, + ); + } +} diff --git a/lib/screens/nav_bar/controller.dart b/lib/screens/nav_bar/controller.dart new file mode 100644 index 0000000..8ff69bb --- /dev/null +++ b/lib/screens/nav_bar/controller.dart @@ -0,0 +1,74 @@ +// import 'package:flutter/animation.dart'; +import 'dart:async'; + +// import 'package:facebook_audience_network/facebook_audience_network.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:meme_baaz/ads/interstitial.dart'; +import 'package:meme_baaz/screens/bookmark/controller.dart'; +import 'package:meme_baaz/screens/player/will_pop.dart'; +import 'package:meme_baaz/screens/upload/controller.dart'; +import 'package:meme_baaz/utils/scroll_to_top.dart'; + +class MyNavBarController extends GetxService { + // ignore: prefer_final_fields + RxInt _index = 0.obs; + RxBool showFab = false.obs; + final Rx scrollController = ScrollController().obs; + + int get index => _index.value; + + set index(int value) { + if (_index.value == 2 && value != 2) { + Get.delete(); + } + if (_index.value == 1 && value != 1) { + Get.delete(); + } + if (_index.value == 0 && value == 0) { + final position = scrollController.value.position.pixels; + if (position > 350) { + scrollToTop(scrollController.value); + } + } + _index.value = value; + showInterstitialAds(5); + } + + Future willpopscope() async { + if (_index.value == 2) { + // ignore: unawaited_futures + Get.delete(); + } + if (_index.value == 1) { + // ignore: unawaited_futures + Get.delete(); + } + if (_index.value != 0) { + _index.value = 0; + } + if (scrollController.value.position.pixels < 350) { + await onBackPressed(Get.context!); + } else { + await scrollToTop(scrollController.value); + } + return false; + } + + @override + void onInit() { + scrollController.value.addListener(() { + if (scrollController.value.position.pixels > 350) { + showFab.value = true; + } else { + showFab.value = false; + } + }); + setTestDevices(); + super.onInit(); + } + + Future setTestDevices() async { + // await FacebookAudienceNetwork.init(testingId: '88907077-a581-4eb3-a37b-e9a9500db5be'); + } +} diff --git a/lib/screens/nav_bar/view.dart b/lib/screens/nav_bar/view.dart new file mode 100644 index 0000000..da7a168 --- /dev/null +++ b/lib/screens/nav_bar/view.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:line_icons/line_icons.dart'; +import 'package:animations/animations.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/constant/theme.dart'; +import 'package:meme_baaz/screens/aboutUs/view.dart'; +import 'package:meme_baaz/screens/bookmark/view.dart'; +import 'package:meme_baaz/screens/home/view.dart'; +import 'package:meme_baaz/screens/upload/view.dart'; +// import 'package:meme_baaz/screens/home/view2.dart'; +// import 'package:meme_baaz/screens/upload/view.dart'; + +import 'controller.dart'; + +class MyNavBar extends StatelessWidget { + + final MyNavBarController controller = Get.put(MyNavBarController()); + + List get _screens => [const HomePage(), const UploadPage(), const Bookmarks(), const AboutPage()]; + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: controller.willpopscope, + child: Obx( + () => Scaffold( + body: PageTransitionSwitcher( + duration: const Duration(milliseconds: 150), + transitionBuilder: (child, primaryAnimation, secondaryAnimation) { + return FadeThroughTransition( + animation: primaryAnimation, + secondaryAnimation: secondaryAnimation, + child: child, + ); + }, + child: _screens[controller.index], + ), + bottomNavigationBar: BottomNavigationBar( + unselectedItemColor: Get.theme.colorScheme.secondary, + fixedColor: themeColor, + elevation: 5, + currentIndex: controller.index, + showUnselectedLabels: true, + showSelectedLabels: true, + selectedLabelStyle: ptSansFont(12.5), + unselectedLabelStyle: ptSansFont(11), + onTap: (int value) => controller.index = value, + items: [ + navItems(LineIcons.home, 'Home'), + navItems(Icons.file_upload_outlined, 'Upload'), + navItems(LineIcons.bookmark, 'Saved'), + navItems(LineIcons.infoCircle, 'More'), + ], + ), + ), + ), + ); + } + + BottomNavigationBarItem navItems(IconData icon, String label) => BottomNavigationBarItem( + icon: Icon(icon, size: myFontSize(24)), + label: label, + ); +} diff --git a/lib/screens/player/icons.dart b/lib/screens/player/icons.dart new file mode 100644 index 0000000..49ce7aa --- /dev/null +++ b/lib/screens/player/icons.dart @@ -0,0 +1,187 @@ +// ignore_for_file: deprecated_member_use + +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; +import 'package:like_button/like_button.dart'; +import 'package:line_icons/line_icons.dart'; +import 'package:meme_baaz/ads/interstitial.dart'; +import 'package:meme_baaz/constant/keys.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/database/database.dart'; +import 'package:meme_baaz/models/content.dart'; +import 'package:meme_baaz/utils/download.dart'; +import 'package:meme_baaz/utils/share.dart'; + +class ContentIcons extends StatefulWidget { + final ContentModel contentModel; + + const ContentIcons({ + required this.contentModel, + Key? key, + }) : super(key: key); + + @override + _ContentIconsState createState() => _ContentIconsState(); +} + +class _ContentIconsState extends State { + final box = GetStorage(); + + ContentModel get content => widget.contentModel; + + // int likes = 0; + + bool isLike = false; + bool isSave = false; + + @override + void initState() { + boxinit(); + boxListeners(); + + super.initState(); + } + + void boxListeners() { + box.listenKey(StorageKeys.like, (value) { + if (value is List) { + if (value.contains(content.id)) { + isLike = true; + } else { + isLike = false; + } + if (mounted) setState(() {}); + // print(likes); + } + }); + box.listenKey(StorageKeys.save, (value) { + if (value is List) { + if (value.contains(content.id)) { + isSave = true; + } else { + isSave = false; + } + if (mounted) setState(() {}); + // print(likes); + } + }); + } + + void boxinit() { + final value = box.read(StorageKeys.like); + if (value is List) { + if (value.contains(content.id)) { + isLike = true; + } else { + isLike = false; + } + if (mounted) setState(() {}); + } + final save = box.read(StorageKeys.save); + if (save is List) { + if (save.contains(content.id)) { + isSave = true; + } else { + isSave = false; + } + if (mounted) setState(() {}); + } + } + + Future like(_) { + final likes = box.read(StorageKeys.like); + if (likes is List) { + Timer(10.seconds, () => showInterstitialAds(5)); + if (isLike) { + likes.remove(content.id); + box.write(StorageKeys.like, likes); + Database.addLike(content.id!, false); + return Future.value(false); + } else { + likes.add(content.id); + box.write(StorageKeys.like, likes); + Database.addLike(content.id!, true); + return Future.value(true); + } + } + return Future.value(false); + } + + Future save(_) async { + final saves = box.read(StorageKeys.save); + if (saves is List) { + if (isSave) { + saves.remove(content.id); + await box.write(StorageKeys.save, saves); + } else { + // ignore: unawaited_futures + showInterstitialAds(); + saves.add(content.id); + await box.write(StorageKeys.save, saves); + } + } + return true; + } + + @override + Widget build(BuildContext context) { + return Row( + children: [ + sizedBoxW(18), + LikeButton( + isLiked: isLike, + onTap: like, + size: myFontSize(30), + circleColor: CircleColor(start: Get.theme.accentColor, end: Get.theme.accentColor), + bubblesColor: BubblesColor( + dotPrimaryColor: Get.theme.colorScheme.secondary, + dotSecondaryColor: Get.theme.accentColor, + ), + likeBuilder: (bool isLiked) { + return Icon( + isLike ? LineIcons.heartAlt : LineIcons.heart, + ); + }, + likeCount: content.likes, + ), + sizedBoxW(8), + IconButton( + splashColor: Colors.transparent, + highlightColor: Colors.transparent, + onPressed: () { + // ignore: unawaited_futures + showInterstitialAds(); + shareMedia(content); + }, + icon: const Icon(LineIcons.share), + ), + const Spacer(), + IconButton( + splashColor: Colors.transparent, + highlightColor: Colors.transparent, + onPressed: () { + showInterstitialAds(); + downloadMedia(content); + }, + icon: const Icon(LineIcons.download), + ), + sizedBoxW(8), + LikeButton( + isLiked: isSave, + onTap: save, + size: myFontSize(30), + circleColor: CircleColor(start: Get.theme.accentColor, end: Get.theme.accentColor), + bubblesColor: BubblesColor( + dotPrimaryColor: Get.theme.accentColor, + dotSecondaryColor: Get.theme.accentColor, + ), + likeBuilder: (_) => Icon(isSave ? Icons.bookmark : LineIcons.bookmark), + ), + sizedBoxW(10), + ], + ); + } +} diff --git a/lib/screens/player/media.dart b/lib/screens/player/media.dart new file mode 100644 index 0000000..757c714 --- /dev/null +++ b/lib/screens/player/media.dart @@ -0,0 +1,199 @@ +import 'package:cached_video_player/cached_video_player.dart'; +import 'package:flutter/material.dart'; +import 'package:get_storage/get_storage.dart'; +import 'package:meme_baaz/ads/interstitial.dart'; +import 'package:meme_baaz/constant/keys.dart'; +import 'package:meme_baaz/constant/style.dart'; +// import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/database/database.dart'; +import 'package:meme_baaz/models/content.dart'; +import 'package:meme_baaz/widgets/cache_image.dart'; +import 'package:flare_flutter/flare_actor.dart'; +import 'package:flare_flutter/flare_controls.dart'; +import 'package:octo_image/octo_image.dart'; +import 'package:visibility_detector/visibility_detector.dart'; + +class ContentMedia extends StatefulWidget { + final ContentModel content; + final bool like; + + const ContentMedia({ + required this.content, + required Key key, + this.like = true, + }) : super(key: key); + + @override + _ContentMediaState createState() => _ContentMediaState(); +} + +class _ContentMediaState extends State { + bool isLike = false; + final FlareControls flareControls = FlareControls(); + final box = GetStorage(); + CachedVideoPlayerController? _controller; + bool isPlayerInit = false; + bool isPaused = false; + + ContentModel get content => widget.content; + + @override + void initState() { + initVideoPlayer(content); + boxinit(); + boxListeners(); + super.initState(); + } + + @override + void dispose() { + _controller?.dispose(); + super.dispose(); + } + + Future initVideoPlayer(ContentModel contentModel) async { + print(contentModel.url!); + if (isPlayerInit == false && contentModel.type == 'video') { + isPlayerInit = true; + _controller = CachedVideoPlayerController.network(contentModel.url!); + await _controller!.initialize(); + await _controller?.setLooping(true); + if (mounted) { + setState(() {}); + } + } + } + + void boxListeners() { + box.listenKey(StorageKeys.like, (value) { + if (value is List) { + if (value.contains(content.id)) { + isLike = true; + } else { + isLike = false; + } + } + }); + } + + void boxinit() { + final value = box.read(StorageKeys.like); + if (value is List) { + if (value.contains(content.id)) { + isLike = true; + } else { + isLike = false; + } + } + } + + void likeEffect() async { + if (widget.like == false) return; + flareControls.play('like'); + final likes = box.read(StorageKeys.like); + if (likes is List) { + // ignore: unawaited_futures + showInterstitialAds(20); + if (!isLike) { + likes.add(content.id); + await box.write(StorageKeys.like, likes); + await Database.addLike(content.id!, true); + } + } + } + + @override + Widget build(BuildContext context) { + Widget loading() { + return SizedBox.expand( + child: OctoPlaceholder.blurHash(hashString)(context), + ); + } + + return VisibilityDetector( + key: (widget.key)!, + onVisibilityChanged: (VisibilityInfo info) { + if (content.type == 'video') { + if (_controller != null) { + if (_controller!.value.isInitialized) { + if (info.visibleFraction > .90) { + if (!isPaused) { + _controller!.play(); + } + } else { + if (_controller!.value.isPlaying && mounted) { + _controller!.pause(); + } + } + } + } + } + }, + child: GestureDetector( + onDoubleTap: likeEffect, + onTap: () { + if (content.type == 'video') { + if (_controller!.value.isPlaying) { + isPaused = true; + _controller!.pause(); + } else { + isPaused = false; + _controller!.play(); + } + } + }, + child: SizedBox( + height: (screenHeight / 5.5) + 280, + width: screenWidth, + child: Stack( + alignment: Alignment.center, + children: [ + ConstrainedBox( + constraints: BoxConstraints( + maxHeight: screenHeight / 1.8, + minWidth: screenWidth, + maxWidth: screenWidth, + minHeight: 100, + ), + child: () { + if (widget.content.type == 'image') { + return cacheImage(widget.content.url!, boxFit: BoxFit.fitWidth); + } else if (widget.content.type == 'video') { + if (_controller != null) { + if (_controller!.value.isInitialized) { + return FittedBox( + clipBehavior: Clip.hardEdge, + fit: BoxFit.cover, + child: SizedBox( + height: _controller!.value.size.height, + width: _controller!.value.size.width, + child: CachedVideoPlayer(_controller!), + ), + ); + } else { + return loading(); + } + } else { + return loading(); + } + } + return Text('error : ${widget.content.id}'); + }(), + ), + SizedBox( + height: 80, + width: 80, + child: FlareActor( + 'assets/instagram_like.flr', + controller: flareControls, + color: Colors.red.shade900, + animation: 'idle', + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/player/shimmers.dart b/lib/screens/player/shimmers.dart new file mode 100644 index 0000000..8795c85 --- /dev/null +++ b/lib/screens/player/shimmers.dart @@ -0,0 +1,92 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:shimmer/shimmer.dart'; + +class TagsShimmer extends StatelessWidget { + const TagsShimmer({ + Key? key, + }) : super(key: key); + @override + Widget build(BuildContext context) { + return Shimmer.fromColors( + baseColor: Get.isDarkMode ? Colors.black45 : Colors.grey[300]!, + highlightColor: Get.isDarkMode ? Colors.black12 : Colors.grey[100]!, + child: Row( + children: List.generate( + 4, + (index) => Expanded( + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 5, vertical: 3), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(100), + ), + ), + ), + ), + ), + ); + } +} + +class ContentShimmer extends StatelessWidget { + const ContentShimmer({ + Key? key, + }) : super(key: key); + @override + Widget build(BuildContext context) { + return Shimmer.fromColors( + baseColor: Get.isDarkMode ? Colors.black45 : Colors.grey[300]!, + highlightColor: Get.isDarkMode ? Colors.black12 : Colors.grey[100]!, + child: Padding( + padding: const EdgeInsets.only(top: 10), + child: Column( + children: List.generate( + 2, + (index) => Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: myFontSize(13)), + child: Row( + children: List.generate( + 3, + (index) => Expanded( + child: Container( + height: 35, + margin: const EdgeInsets.symmetric(horizontal: 4), + // width: 100, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(5), + ), + ), + ), + ), + ), + ), + sizedBoxH(10), + Padding( + padding: EdgeInsets.symmetric(horizontal: myFontSize(13)), + child: Container( + height: screenHeight / 2, + width: 100, + margin: const EdgeInsets.symmetric(horizontal: 4), + + // margin: EdgeInsets.symmetric(horizontal: 5, vertical: 3), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(5), + ), + ), + ), + sizedBoxH(30), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/player/title.dart b/lib/screens/player/title.dart new file mode 100644 index 0000000..f100634 --- /dev/null +++ b/lib/screens/player/title.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/constant/theme.dart'; +import 'package:meme_baaz/models/content.dart'; +import 'package:readmore/readmore.dart'; + +Padding contentTitleWidget(ContentModel content) { + final tags = content.tags!.map((e) => '#' + e + ' ').join(); + + return Padding( + padding: EdgeInsets.symmetric(vertical: myFontSize(7), horizontal: myFontSize(10)), + child: ReadMoreText( + content.title!.isEmpty ? tags : '${content.title!} \n$tags', + trimLines: 2, + trimMode: TrimMode.Line, + style: ptSansFont(15.5), + lessStyle: ptSansFont(15.0).copyWith(color: themeColor), + moreStyle: ptSansFont(15.0).copyWith(color: themeColor), + // colo + ), + ); +} diff --git a/lib/screens/player/will_pop.dart b/lib/screens/player/will_pop.dart new file mode 100644 index 0000000..a21de7c --- /dev/null +++ b/lib/screens/player/will_pop.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart' show BuildContext; +import 'package:flutter/services.dart' show SystemNavigator; +import 'package:meme_baaz/functions/dialog.dart'; + + +Future onBackPressed(BuildContext context) { + return myDialog( + context: context, + title: 'Are you sure?', + no: 'NO ', + content: 'Do you want to exit an App', + yes: 'YES', + onTap: () => SystemNavigator.pop(), + ); +} diff --git a/lib/screens/upload/controller.dart b/lib/screens/upload/controller.dart new file mode 100644 index 0000000..cdea401 --- /dev/null +++ b/lib/screens/upload/controller.dart @@ -0,0 +1,194 @@ +import 'dart:math'; + +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_storage/firebase_storage.dart'; +import 'package:get/get.dart'; +import 'package:meme_baaz/constant/theme.dart'; +import 'package:meme_baaz/models/content.dart'; +import 'package:meme_baaz/utils/compression.dart'; +import 'package:meme_baaz/models/upload.dart'; +import 'package:meme_baaz/utils/getAspectRatio.dart'; +import 'package:meme_baaz/utils/sizeCheck.dart'; +import 'package:meme_baaz/widgets/assetsdetailspopup.dart'; +import 'package:meme_baaz/functions/getSnack_bar.dart'; +import 'package:wechat_assets_picker/wechat_assets_picker.dart'; + +class UploadController extends GetxController { + RxList categories = [].obs; + RxList selectedAssets = [].obs; + RxList uploadingData = [].obs; + final firestoreInstance = FirebaseFirestore.instance; + + Future fetchCategories() async { + try { + final res = await firestoreInstance.collection('config').doc('categories').get(); + final _data = ((res.data()?['data']).cast()); + categories.assignAll(_data); + } on FirebaseException catch (e) { + await showToast(msg: e.message!); + } + } + + Future loadAssets() async { + try { + final resultList = await AssetPicker.pickAssets( + Get.context!, + pickerConfig: AssetPickerConfig( + maxAssets: 10, + + filterOptions: FilterOptionGroup( + imageOption: const FilterOption( + needTitle: true, + sizeConstraint: SizeConstraint(maxHeight: 3000, maxWidth: 3000, minHeight: 50, minWidth: 50), + ), + videoOption: FilterOption( + durationConstraint: DurationConstraint(max: 3.minutes), + needTitle: true, + ), + ), + requestType: RequestType.common, + selectedAssets: selectedAssets, + textDelegate: EnglishAssetPickerTextDelegate(), + themeColor: themeColor, + ), + ); + + if (resultList == null) { + return; + } + + resultList.removeWhere((e) => selectedAssets.map((e) => e.id).contains(e.id)); + + var totalRemoved = 0; + for (final item in List.from(resultList)) { + final s = await sizeCheck(item); + if (!s) { + resultList.remove(item); + totalRemoved++; + } + } + if (totalRemoved != 0) await showToast(msg: '$totalRemoved assets has over size, removed.', short: false); + + selectedAssets.addAll(resultList); + uploadingData.addAll(resultList.map((e) => UploadingData(id: e.id, tags: [if (e.type == AssetType.image) 'images' else 'videos']))); + uploadAssets(resultList); + } on Exception catch (e) { + await showToast(msg: e.toString()); + } + } + + void uploadAssets(List? assetEntities) { + for (final asset in assetEntities!) { + final path = 'content/${Random().nextInt(100000)}-${asset.title!.removeAllWhitespace}'; + + if (asset.type == AssetType.video) { + asset.file.then((videoData) { + if (uploadingData.where((e) => e.id == asset.id).isNotEmpty) { + final model = uploadingData.singleWhere((e) => e.id == asset.id); + final i = uploadingData.indexOf(model); + uploadingData[i] = model.copyWith(uploadingStatus: UploadingStatus.uploading); + } + FirebaseStorage.instance.ref().child(path).putFile(videoData!).then((_task) { + if (uploadingData.where((e) => e.id == asset.id).isNotEmpty) { + final model = uploadingData.singleWhere((e) => e.id == asset.id); + final i = uploadingData.indexOf(model); + final downUrl = 'https://storage.googleapis.com/${_task.ref.bucket}/${_task.ref.fullPath}'; + uploadingData[i] = model.copyWith(url: downUrl, uploadingStatus: UploadingStatus.ready); + } + }); + }); + + // final videoData = await videoCompress(await asset.file); + } else if (asset.type == AssetType.image) { + asset.file.then((_file) { + imageCompress(_file).then((imageData) { + if (uploadingData.where((e) => e.id == asset.id).isNotEmpty) { + final model = uploadingData.singleWhere((e) => e.id == asset.id); + final i = uploadingData.indexOf(model); + uploadingData[i] = model.copyWith(uploadingStatus: UploadingStatus.uploading); + } + FirebaseStorage.instance.ref().child(path).putData(imageData).then((_task) { + if (uploadingData.where((e) => e.id == asset.id).isNotEmpty) { + final model = uploadingData.singleWhere((e) => e.id == asset.id); + final i = uploadingData.indexOf(model); + final downUrl = 'https://storage.googleapis.com/${_task.ref.bucket}/${_task.ref.fullPath}'; + uploadingData[i] = model.copyWith(url: downUrl, uploadingStatus: UploadingStatus.ready); + // print(downUrl); + } + }); + }); + }); + } + } + } + + void deleteAsset(AssetEntity assetEntity) { + selectedAssets.removeWhere((e) => e.id == assetEntity.id); + uploadingData.removeWhere((e) => e.id == assetEntity.id); + } + + Future upload() async { + final _pendings = uploadingData.where((b) => b.uploadingStatus != UploadingStatus.ready).length; + if (_pendings != 0) { + await showToast(msg: 'All the assets must ready.'); + return; + } + final _urlCheck = uploadingData.where((b) => b.url == null).length; + if (_urlCheck != 0) { + await showToast(msg: 'url issue, contact developer.'); + return; + } + final _tagsCheck = uploadingData.where((b) => b.tags.isEmpty).length; + if (_tagsCheck != 0) { + await showToast(msg: 'All the assets must have atleast one tag.'); + return; + } + + if (uploadingData.length != selectedAssets.length) { + await showToast(msg: 'something mismatch, contact developer.'); + } + + var totalUploaded = 0; + await showToast(msg: 'Uploading.'); + + for (var i = 0; i < selectedAssets.length; i++) { + final asset = selectedAssets[i]; + final assetData = uploadingData.singleWhere((e) => asset.id == e.id); + + final content = ContentModel( + dateUploaded: DateTime.now(), + likes: 0, + size: await getAssetSize(asset), + status: ContentStatus.pending, + url: assetData.url, + type: asset.type == AssetType.image ? 'image' : 'video', + title: assetData.title, + tags: assetData.tags, + aspectRatio: getAspectRatio(asset), + ); + try { + await firestoreInstance.collection('content').add(content.toJson()); + totalUploaded++; + } on FirebaseException catch (e) { + await showToast(msg: e.message!); + } + } + selectedAssets.clear(); + uploadingData.clear(); + if (totalUploaded != 0) await showToast(msg: '$totalUploaded assets uploaded.'); + } + + Future titleTextField(AssetEntity asset) async { + final i = uploadingData.indexWhere((e) => e.id == asset.id); + final model = uploadingData[i]; + final r = await showTitleTextField(Get.context!, model); + if (r == null) return; + uploadingData[i] = model.copyWith(title: r); + } + + @override + void onInit() { + fetchCategories(); + super.onInit(); + } +} diff --git a/lib/screens/upload/privacy_policy.dart b/lib/screens/upload/privacy_policy.dart new file mode 100644 index 0000000..48b6f0f --- /dev/null +++ b/lib/screens/upload/privacy_policy.dart @@ -0,0 +1,53 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/constant/theme.dart'; + +void showUploadPrivacyPolicy(BuildContext context) { + showCupertinoDialog( + context: context, + barrierDismissible: true, + builder: (context) { + final ptSans2 = ptSansFont(14.2); + // ignore: deprecated_member_use + final title = (String t) => Text(t, style: ptSans2.copyWith(color: Get.theme.accentColor, fontWeight: FontWeight.w600)); + // ignore: deprecated_member_use + final detail = (String t) => Text(t, style: ptSansFont().copyWith(color: Get.theme.accentColor.withOpacity(.6))); + var sizedBoxH2 = sizedBoxH(25); + return AlertDialog( + title: Text('PRIVACY & POLICY', style: ptSans2.copyWith(fontWeight: FontWeight.bold)), + content: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + title('Size limit?'), + detail('Max asset size 5MB.'), + sizedBoxH2, + sizedBoxH2, + title('What to upload?'), + detail('memes and funny short videos.'), + sizedBoxH2, + sizedBoxH2, + title('What to not upload?'), + detail('adult and sexual content.'), + sizedBoxH2, + sizedBoxH2, + title('Availability'), + detail('Every asset will go through a verification process by admin before publicly available.'), + sizedBoxH2, + sizedBoxH2, + title('Why whould we even upload?'), + detail('it\'s hard to find unique content for us so if you have something funny upload it here so the app will keep running.'), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('OK', style: ptSans2.copyWith(color: themeColor)), + ), + ], + ); + }, + ); +} diff --git a/lib/screens/upload/video_player.dart b/lib/screens/upload/video_player.dart new file mode 100644 index 0000000..8fae66f --- /dev/null +++ b/lib/screens/upload/video_player.dart @@ -0,0 +1,122 @@ +import 'package:cached_video_player/cached_video_player.dart'; +import 'package:flutter/material.dart'; +import 'package:meme_baaz/constant/style.dart'; +// import 'package:meme_baaz/constant/style.dart'; +import 'package:octo_image/octo_image.dart'; +import 'package:visibility_detector/visibility_detector.dart'; +import 'package:wechat_assets_picker/wechat_assets_picker.dart'; + +class AssetVideoPlayer extends StatefulWidget { + const AssetVideoPlayer({ + required this.assetEntity, + required Key key, + }) : super(key: key); + + final AssetEntity assetEntity; + + @override + _AssetVideoPlayerState createState() => _AssetVideoPlayerState(); +} + +class _AssetVideoPlayerState extends State { + CachedVideoPlayerController? _controller; + bool isPlayerInit = false; + bool isPaused = false; + + @override + void initState() { + initVideoPlayer(widget.assetEntity); + super.initState(); + } + + @override + void dispose() { + _controller?.dispose(); + super.dispose(); + } + + Future initVideoPlayer(AssetEntity assetEntity) async { + if (isPlayerInit == false) { + isPlayerInit = true; + final file = await assetEntity.file; + _controller = CachedVideoPlayerController.file(file!); + await _controller!.initialize(); + await _controller?.setLooping(true); + if (mounted) { + setState(() {}); + } + } + } + + @override + Widget build(BuildContext context) { + Widget loading() { + return SizedBox( + height: screenHeight / 1.5, + width: screenWidth, + child: OctoPlaceholder.blurHash(hashString)(context), + ); + } + + return VisibilityDetector( + key: (widget.key)!, + onVisibilityChanged: (VisibilityInfo info) { + if (_controller != null) { + if (_controller!.value.isInitialized) { + if (info.visibleFraction > .90) { + if (!isPaused) { + _controller!.play(); + } + } else { + if (_controller!.value.isPlaying && mounted) { + _controller!.pause(); + } + } + } + } + }, + child: GestureDetector( + onTap: () { + if (_controller!.value.isPlaying) { + isPaused = true; + _controller!.pause(); + } else { + isPaused = false; + _controller!.play(); + } + }, + child: SizedBox( + height: (screenHeight / 3.5) + 170, + width: screenWidth, + child: ConstrainedBox( + constraints: BoxConstraints( + maxHeight: screenHeight / 1.8, + minWidth: screenWidth, + maxWidth: screenWidth, + minHeight: 100, + ), + child: () { + if (_controller != null) { + if (_controller!.value.isInitialized) { + return FittedBox( + clipBehavior: Clip.hardEdge, + fit: BoxFit.cover, + child: SizedBox( + height: _controller!.value.size.height, + width: _controller!.value.size.width, + child: CachedVideoPlayer(_controller!), + ), + ); + } else { + return loading(); + } + } else { + return loading(); + } + }(), + ), + ), + ), + ); + } +} diff --git a/lib/screens/upload/view.dart b/lib/screens/upload/view.dart new file mode 100644 index 0000000..e9763c9 --- /dev/null +++ b/lib/screens/upload/view.dart @@ -0,0 +1,298 @@ +// ignore_for_file: deprecated_member_use + +import 'dart:io'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:get/get.dart'; +import 'package:meme_baaz/constant/theme.dart'; +import 'package:meme_baaz/functions/getSnack_bar.dart'; +import 'package:meme_baaz/screens/upload/video_player.dart'; +import 'package:meme_baaz/models/upload.dart'; +import 'package:meme_baaz/screens/upload/controller.dart'; +import 'package:meme_baaz/widgets/assetsdetailspopup.dart'; +import 'package:meme_baaz/widgets/decoration.dart'; +import 'package:meme_baaz/widgets/gradient_button.dart'; +import 'package:wechat_assets_picker/wechat_assets_picker.dart'; + +import 'privacy_policy.dart'; + +class UploadPage extends StatelessWidget { + const UploadPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final controller = Get.put(UploadController()); + return GestureDetector( + onTap: () => WidgetsBinding.instance.focusManager.primaryFocus!.unfocus(), + child: Scaffold( + appBar: AppBar( + title: Text('Upload Memes', style: ptSansFont()), + elevation: 0, + actions: [ + Obx(() { + if (controller.selectedAssets.isEmpty) { + return const SizedBox.shrink(); + } + return IconButton( + onPressed: null, + icon: Text('${controller.selectedAssets.length}/15', style: ptSansFont()), + ); + }), + ], + ), + body: Obx( + () => SingleChildScrollView( + child: Column( + children: [ + for (int i = 0; i < controller.selectedAssets.length; i++) + Container( + margin: const EdgeInsets.symmetric(vertical: 10), + padding: EdgeInsets.zero, + decoration: buildDecoration(radius: 5), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + sizedBoxH(10), + Padding( + padding: EdgeInsets.all(myFontSize(5)), + child: Row( + children: [ + Text('${i + 1}. ', style: ptSansFont(15.5).copyWith(fontWeight: FontWeight.bold)), + Text(controller.selectedAssets[i].title!, style: ptSansFont(14.5)), + ], + ), + ), + const Divider(height: 5), + sizedBoxH(10), + () { + final asset = controller.selectedAssets[i]; + final loading = SizedBox( + height: screenHeight / 1.5, + width: screenWidth, + child: const Center(child: CupertinoActivityIndicator()), + ); + if (asset.type == AssetType.image) { + return Image(image: AssetEntityImageProvider(asset)); + } else if (asset.type == AssetType.video) { + return FutureBuilder( + future: asset.file, + builder: (context, snapshot) { + if (!snapshot.hasData || snapshot.data?.path == null) { + return loading; + } + return AssetVideoPlayer(assetEntity: asset, key: Key(asset.id)); + }, + ); + } + return SizedBox( + height: 200, + width: screenWidth, + child: Center(child: Text('Something went wrong', style: ptSansFont(20))), + ); + }(), + sizedBoxH(10), + textField(i), + buildButtons(i), + sizedBoxH(5), + buildAssetType(i), + sizedBoxH(5), + ], + ), + ), + if (controller.selectedAssets.length < 15) + GestureDetector( + onTap: controller.loadAssets, + child: Container( + height: controller.selectedAssets.isEmpty ? screenHeight - 200 : 200, + width: screenWidth, + decoration: BoxDecoration( + border: Border.all(width: .5, color: Get.theme.accentColor), + borderRadius: BorderRadius.circular(5), + ), + margin: const EdgeInsets.all(10), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.upload_file_outlined, size: myFontSize(35)), + sizedBoxH(30), + Text('Choose files to upload', textAlign: TextAlign.center, style: ptSansFont()), + sizedBoxH(10), + CupertinoButton( + onPressed: () => showUploadPrivacyPolicy(context), + child: Text('PRIVACY & POLICY', style: ptSansFont(12).copyWith(color: themeColor)), + ), + ], + ), + ), + ), + if (controller.selectedAssets.isNotEmpty) + Padding( + padding: const EdgeInsets.all(10.0), + child: CustomButton( + height: myFontSize(50), + width: screenWidth, + radius: 5, + text: 'Upload', + onTap: controller.upload, + ), + ) + ], + ), + ), + ), + ), + ); + } + + Widget buildAssetType(int index) { + return Obx( + () { + final controller = Get.find(); + if (controller.categories.isEmpty) { + return const SizedBox.shrink(); + } + final asset = controller.selectedAssets[index]; + final assetData = controller.uploadingData.singleWhere((e) => e.id == asset.id); + final uploadingindex = controller.uploadingData.indexOf(assetData); + return Padding( + padding: const EdgeInsets.all(4.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text('Meme Tags -', style: ptSansFont()), + Wrap( + children: [ + for (final cate in controller.categories.where((c) { + if (asset.type == AssetType.image && c == 'videos') { + return false; + } else if (asset.type == AssetType.video && c == 'images') { + return false; + } + return true; + })) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 5), + child: RawChip( + deleteIconColor: Colors.white, + onDeleted: assetData.tags.contains(cate) + ? () { + if (cate == 'videos' || cate == 'images') { + showToast(msg: "asset type can't be removed."); + return; + } + final _type = assetData.tags; + _type.remove(cate); + controller.uploadingData[uploadingindex] = assetData.copyWith(tags: _type); + } + : null, + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: .1), + selectedColor: themeColor, + backgroundColor: Get.isDarkMode ? Colors.white10 : Colors.black12, + selected: assetData.tags.contains(cate), + showCheckmark: false, + onSelected: (b) { + if (b) { + final _type = List.from(assetData.tags); + _type.add(cate); + controller.uploadingData[uploadingindex] = assetData.copyWith(tags: _type); + } + }, + label: Text( + cate.capitalize!, + style: ptSansFont(14).copyWith( + color: assetData.tags.contains(cate) ? Colors.white : Get.theme.accentColor, + ), + ), + ), + ), + ], + ), + ], + ), + ); + }, + ); + } + + Widget buildButtons(int i) { + return Obx( + () { + final controller = Get.find(); + return Padding( + padding: const EdgeInsets.all(4.0), + child: Row( + children: [ + OutlinedButton( + onPressed: () { + final asset = controller.selectedAssets[i]; + final uploadingData = controller.uploadingData.singleWhere((e) => e.id == asset.id); + showAssetsDetailsPopup(asset, uploadingData); + }, + child: Icon( + Icons.info, + color: Get.theme.accentColor, + ), + ), + sizedBoxW(10), + Expanded( + flex: 70, + child: OutlinedButton( + onPressed: null, + child: () { + final asset = controller.selectedAssets[i]; + final uploadingData = controller.uploadingData.singleWhere((e) => e.id == asset.id); + if (uploadingData.uploadingStatus == UploadingStatus.ready) { + return Text( + getUploadingStatus(uploadingData.uploadingStatus), + overflow: TextOverflow.ellipsis, + style: ptSansFont(13.5).copyWith(color: Colors.green.shade600), + ); + } + return Text(getUploadingStatus(uploadingData.uploadingStatus), overflow: TextOverflow.ellipsis, style: ptSansFont(13.5)); + }(), + ), + ), + sizedBoxW(10), + Expanded( + flex: 100, + child: OutlinedButton( + onPressed: () => controller.deleteAsset(controller.selectedAssets[i]), + child: Text('Delete', style: ptSansFont().copyWith(color: Colors.red.shade600, fontWeight: FontWeight.w500)), + ), + ), + ], + ), + ); + }, + ); + } + + GestureDetector textField(int i) { + final controller = Get.find(); + return GestureDetector( + onTap: () => controller.titleTextField(controller.selectedAssets[i]), + child: Obx( + () { + final asset = controller.selectedAssets[i]; + final title = controller.uploadingData.singleWhere((e) => e.id == asset.id).title; + return Container( + margin: const EdgeInsets.all(4), + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + border: Border.all(color: Get.theme.accentColor.withOpacity(.5)), + borderRadius: BorderRadius.circular(5), + ), + child: title.isNotEmpty + ? Text(title, style: ptSansFont()) + : Text( + 'Title', + style: ptSansFont().copyWith(color: Get.theme.accentColor.withOpacity(.5)), + ), + ); + }, + ), + ); + } +} diff --git a/lib/utils/cache_files.dart b/lib/utils/cache_files.dart new file mode 100644 index 0000000..11d6351 --- /dev/null +++ b/lib/utils/cache_files.dart @@ -0,0 +1,14 @@ +import 'dart:io'; + +import 'package:flutter_cache_manager/flutter_cache_manager.dart'; + +Future fetchCacheVideo(String url) async { + final cacheManager = DefaultCacheManager(); + FileInfo? fileInfo; + fileInfo = await cacheManager.getFileFromCache(url); + if (fileInfo?.file == null) { + print(url); + fileInfo = await cacheManager.downloadFile(url); + } + return fileInfo?.file; +} diff --git a/lib/utils/compression.dart b/lib/utils/compression.dart new file mode 100644 index 0000000..7bf9a0a --- /dev/null +++ b/lib/utils/compression.dart @@ -0,0 +1,23 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter_image_compress/flutter_image_compress.dart'; +// import 'package:video_compress/video_compress.dart'; + +Future imageCompress(File? file) async { + return await FlutterImageCompress.compressWithList( + file!.readAsBytesSync(), + minWidth: 700, + minHeight: 700, + quality: 93, + ); +} + +// Future videoCompress(File? file) async { +// return file!; +// MediaInfo? mediaInfo = await VideoCompress.compressVideo(file!.path, includeAudio: true,); +// if (mediaInfo == null) { +// return file; +// } +// return mediaInfo.file!; +// } diff --git a/lib/utils/download.dart b/lib/utils/download.dart new file mode 100644 index 0000000..6bfc905 --- /dev/null +++ b/lib/utils/download.dart @@ -0,0 +1,16 @@ +import 'package:image_gallery_saver/image_gallery_saver.dart'; +import 'package:meme_baaz/functions/getSnack_bar.dart'; +import 'package:meme_baaz/models/content.dart'; + +import 'cache_files.dart'; + +Future downloadMedia(ContentModel content) async { + final _file = await fetchCacheVideo(content.url!); + if (content.type == 'image') { + await ImageGallerySaver.saveImage(await _file!.readAsBytes()); + await showToast(msg: 'Saved successfully'); + } else { + await ImageGallerySaver.saveFile(_file!.path); + await showToast(msg: 'Saved successfully'); + } +} diff --git a/lib/utils/getAspectRatio.dart b/lib/utils/getAspectRatio.dart new file mode 100644 index 0000000..f157a4f --- /dev/null +++ b/lib/utils/getAspectRatio.dart @@ -0,0 +1,9 @@ +import 'package:flutter/cupertino.dart'; +import 'package:wechat_assets_picker/wechat_assets_picker.dart'; + +double getAspectRatio(AssetEntity assetEntity) { + if (assetEntity.orientation == 270) { + return Size(assetEntity.height.toDouble(), assetEntity.width.toDouble()).aspectRatio; + } + return assetEntity.size.aspectRatio; +} diff --git a/lib/utils/scroll_to_top.dart b/lib/utils/scroll_to_top.dart new file mode 100644 index 0000000..bd0b364 --- /dev/null +++ b/lib/utils/scroll_to_top.dart @@ -0,0 +1,12 @@ +import 'package:flutter/cupertino.dart'; + +Future scrollToTop(ScrollController scrollController) async { + scrollController.jumpTo( + scrollController.position.minScrollExtent + 350, + ); + await scrollController.animateTo( + scrollController.position.minScrollExtent, + duration: const Duration(milliseconds: 300), + curve: Curves.fastOutSlowIn, + ); +} diff --git a/lib/utils/share.dart b/lib/utils/share.dart new file mode 100644 index 0000000..1db7d89 --- /dev/null +++ b/lib/utils/share.dart @@ -0,0 +1,17 @@ +import 'package:meme_baaz/models/content.dart'; +import 'package:wc_flutter_share/wc_flutter_share.dart'; + +import 'cache_files.dart'; + +Future shareMedia(ContentModel content) async { + final type = content.url!.split('.').last; + final _file = await fetchCacheVideo(content.url!); + await WcFlutterShare.share( + sharePopupTitle: 'share', + subject: 'Meme from MemeBaaz app', + text: 'Downlaod MemeBaaz app now : https://play.google.com/store/apps/details?id=com.memebaaz.MemeBaaz', + fileName: 'memebaaz_video.$type', + mimeType: '${content.type}/$type', + bytesOfFile: await _file!.readAsBytes(), + ); +} diff --git a/lib/utils/sizeCheck.dart b/lib/utils/sizeCheck.dart new file mode 100644 index 0000000..9b255d4 --- /dev/null +++ b/lib/utils/sizeCheck.dart @@ -0,0 +1,29 @@ +import 'package:wechat_assets_picker/wechat_assets_picker.dart'; + +Future sizeCheck( assetEntity) async { + final _file = await assetEntity.file; + final _bytes = await _file!.length(); + final _size = _bytes / 1000000; + + if (assetEntity.type == AssetType.image) { + if (_size < 5.0) { + return true; + } else { + return false; + } + } else if (assetEntity.type == AssetType.video) { + if (_size < 5.0) { + return true; + } else { + return false; + } + } + + return false; +} + +Future getAssetSize(AssetEntity assetEntity) async { + final _file = await assetEntity.file; + final _bytes = await _file!.length(); + return double.parse((_bytes / 1000000).toStringAsFixed(2)); +} diff --git a/lib/widgets/assetsdetailspopup.dart b/lib/widgets/assetsdetailspopup.dart new file mode 100644 index 0000000..ba43f0c --- /dev/null +++ b/lib/widgets/assetsdetailspopup.dart @@ -0,0 +1,130 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/constant/theme.dart'; +import 'package:meme_baaz/models/upload.dart'; +import 'package:wechat_assets_picker/wechat_assets_picker.dart'; +import 'package:get/get.dart'; + +void showAssetsDetailsPopup(AssetEntity assetEntityModel, UploadingData uploadingData) { + showCupertinoDialog( + context: Get.context!, + barrierDismissible: true, + builder: (context) { + final ptSans2 = ptSansFont(14.2); + // ignore: deprecated_member_use + final title = (String t) => Text(t, style: ptSans2.copyWith(color: Get.theme.accentColor.withOpacity(.7))); + final detail = (String t) => Text(t, style: ptSansFont().copyWith(fontWeight: FontWeight.w500)); + var sizedBoxH2 = sizedBoxH(25); + return AlertDialog( + title: Text('Details', style: ptSans2.copyWith(fontWeight: FontWeight.bold)), + content: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + title('Name'), + detail(assetEntityModel.title!), + sizedBoxH2, + sizedBoxH2, + title('Location'), + detail(assetEntityModel.relativePath!), + if (assetEntityModel.type == AssetType.video) ...[ + sizedBoxH2, + title('Video Duration'), + detail((assetEntityModel.duration / 60).toStringAsFixed(2) + ' Minutes'), + ], + sizedBoxH2, + title('Size'), + FutureBuilder( + future: () async { + final f = await assetEntityModel.file; + return await f!.length(); + }(), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return detail(''); + } + return detail((snapshot.data! / 1000000).toStringAsFixed(2) + ' MB'); + }, + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('OK', style: ptSans2.copyWith(color: themeColor)), + ), + ], + ); + }, + ); +} + +Future showTitleTextField(BuildContext context, UploadingData uploadingData) async { + return showCupertinoDialog( + context: context, + barrierDismissible: true, + builder: (context) { + String? _value = uploadingData.title; + final ptSans2 = ptSansFont(); + return AlertDialog( + content: FormBuilderTextField( + autovalidateMode: AutovalidateMode.onUserInteraction, + name: uploadingData.id, + buildCounter: _wordCounter, + onChanged: (v) => _value = v, + initialValue: uploadingData.title, + style: ptSans2, + maxLines: 2, + maxLength: 350, + decoration: _decoration('Title'), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('Cancel', style: ptSansFont().copyWith(color: themeColor)), + ), + TextButton( + onPressed: () => Navigator.pop(context, _value), + child: Text('Ok', style: ptSansFont().copyWith(color: themeColor)), + ), + ], + ); + }, + ); +} + +Widget _wordCounter(context, {currentLength, isFocused, maxLength}) { + return Text( + '$currentLength/$maxLength', + semanticsLabel: 'character count', + style: ptSansFont(), + ); +} + +InputDecoration _decoration([String? label]) { + const radius = BorderRadius.all(Radius.circular(5.0)); + // TextStyle _style = ptSans(39).copyWith(letterSpacing: 0.3); + return InputDecoration( + hintText: label, + hintStyle: ptSansFont(), + // hintStyle: ptSansFont(), + errorStyle: ptSansFont(), + // isCollapsed: true, + contentPadding: EdgeInsets.symmetric(vertical: 5, horizontal: 10.0), + fillColor: Colors.black, + border: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.black12, width: 2), + borderRadius: radius, + ), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.black12, width: 2), + borderRadius: radius, + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: themeColor, width: 2.0), + borderRadius: radius, + ), + ); +} diff --git a/lib/widgets/cache_image.dart b/lib/widgets/cache_image.dart new file mode 100644 index 0000000..22b2cff --- /dev/null +++ b/lib/widgets/cache_image.dart @@ -0,0 +1,25 @@ +// import 'package:meme_baaz/constant/theme.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +// import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:octo_image/octo_image.dart'; + +Widget cacheImage(String url, {double? width, double? height, BoxFit boxFit = BoxFit.contain}) { + return CachedNetworkImage( + fit: boxFit, + placeholder: (BuildContext context, String url) { + return OctoPlaceholder.blurHash(hashString)(context); + }, + imageUrl: url, + fadeOutCurve: Curves.decelerate, + fadeInCurve: Curves.decelerate, + errorWidget: (context, url, error) => Container( + height: height, + width: width, + color: Colors.white70, + padding: const EdgeInsets.all(12), + child: const Icon(Icons.error_rounded), + ), + ); +} diff --git a/lib/widgets/decoration.dart b/lib/widgets/decoration.dart new file mode 100644 index 0000000..4729a0e --- /dev/null +++ b/lib/widgets/decoration.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:meme_baaz/constant/style.dart'; + +BoxDecoration buildDecoration({double? radius, Color? color}) { + return BoxDecoration( + color: Get.theme.scaffoldBackgroundColor, + borderRadius: BorderRadius.circular(radius ?? myFontSize(35)), + boxShadow: [ + BoxShadow( + color: color ?? Colors.grey.withOpacity(0.10), + offset: const Offset(1.1, 1.1), + blurRadius: 10.0, + ), + ], + ); +} diff --git a/lib/widgets/gradient_button.dart b/lib/widgets/gradient_button.dart new file mode 100644 index 0000000..f725729 --- /dev/null +++ b/lib/widgets/gradient_button.dart @@ -0,0 +1,42 @@ +// import 'package:flutter/cupertino.dart'; +// import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:meme_baaz/constant/style.dart'; +import 'package:meme_baaz/constant/theme.dart'; + +class CustomButton extends StatelessWidget { + final VoidCallback onTap; + final String? text; + final Widget? child; + final double? height; + final double? width; + final double? radius; + const CustomButton({ + required this.onTap, + Key? key, + this.text, + this.height = 140, + this.radius = 10.0, + this.child, + this.width, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return SizedBox( + height: height, + width: width, + child: ElevatedButton( + style: OutlinedButton.styleFrom( + elevation: 1, + textStyle: ptSansFont(), + backgroundColor: themeColor, + side: const BorderSide(width: 0), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(radius!)), + ), + onPressed: onTap, + child: child ?? Text(text!, textAlign: TextAlign.center, style: ptSansFont().copyWith(color: Colors.white)), + ), + ); + } +} diff --git a/lib/widgets/video_playar_memory.dart b/lib/widgets/video_playar_memory.dart new file mode 100644 index 0000000..13718d5 --- /dev/null +++ b/lib/widgets/video_playar_memory.dart @@ -0,0 +1,68 @@ +// import 'dart:io'; + +// import 'package:better_player/better_player.dart'; +// import 'package:flutter/cupertino.dart'; +// import 'package:flutter/material.dart'; +// import 'package:meme_baaz/constant/style.dart'; +// import 'package:wechat_assets_picker/wechat_assets_picker.dart'; + +// class MyVideoPlayer extends StatefulWidget { +// const MyVideoPlayer({ +// Key? key, +// required this.asset, +// }) : super(key: key); + +// final AssetEntity asset; + +// @override +// _MyVideoPlayerState createState() => _MyVideoPlayerState(); +// } + +// class _MyVideoPlayerState extends State { +// File? _file; + +// AssetEntity get asset => widget.asset; + +// @override +// void initState() { +// loadFile(); +// super.initState(); +// } + +// Future loadFile() async { +// final f = await asset.file; +// _file = f!; +// setState(() {}); +// } + + + +// Widget get loading => SizedBox( +// height: 200, +// width: screenWidth, +// child: Center(child: CupertinoActivityIndicator()), +// ); + +// @override +// Widget build(BuildContext context) { +// if (_file == null) { +// return loading; +// } +// return AspectRatio( +// aspectRatio: asset.size.aspectRatio, +// child: BetterPlayer.file( +// _file!.path, +// betterPlayerConfiguration: BetterPlayerConfiguration( +// aspectRatio: widget.asset.size.aspectRatio, +// looping: true, +// controlsConfiguration: BetterPlayerControlsConfiguration( +// enableFullscreen: false, +// enableOverflowMenu: false, +// enablePip: false, +// enableSkips: false, +// ), +// ), +// ), +// ); +// } +// } diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..d67821f --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,936 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + animations: + dependency: "direct main" + description: + name: animations + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.3" + archive: + dependency: transitive + description: + name: archive + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.1" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.1" + async: + dependency: transitive + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.2" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + cached_video_player: + dependency: "direct main" + description: + name: cached_video_player + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.3" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.5" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + cloud_firestore: + dependency: "direct main" + description: + name: cloud_firestore + url: "https://pub.dartlang.org" + source: hosted + version: "3.4.4" + cloud_firestore_platform_interface: + dependency: transitive + description: + name: cloud_firestore_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "5.7.1" + cloud_firestore_web: + dependency: transitive + description: + name: cloud_firestore_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.4" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.16.0" + connectivity: + dependency: "direct main" + description: + name: connectivity + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.6" + connectivity_for_web: + dependency: transitive + description: + name: connectivity_for_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.0+1" + connectivity_macos: + dependency: transitive + description: + name: connectivity_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1+2" + connectivity_platform_interface: + dependency: transitive + description: + name: connectivity_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" + csslib: + dependency: transitive + description: + name: csslib + url: "https://pub.dartlang.org" + source: hosted + version: "0.17.2" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.5" + dio: + dependency: "direct main" + description: + name: dio + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.6" + extended_image: + dependency: transitive + description: + name: extended_image + url: "https://pub.dartlang.org" + source: hosted + version: "6.2.1" + extended_image_library: + dependency: transitive + description: + name: extended_image_library + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.0" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + ffi: + dependency: transitive + description: + name: ffi + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + file: + dependency: transitive + description: + name: file + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.2" + firebase_auth: + dependency: "direct main" + description: + name: firebase_auth + url: "https://pub.dartlang.org" + source: hosted + version: "3.6.3" + firebase_auth_platform_interface: + dependency: transitive + description: + name: firebase_auth_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "6.5.3" + firebase_auth_web: + dependency: transitive + description: + name: firebase_auth_web + url: "https://pub.dartlang.org" + source: hosted + version: "4.2.3" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + url: "https://pub.dartlang.org" + source: hosted + version: "1.20.1" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "4.5.0" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.1" + firebase_messaging: + dependency: "direct main" + description: + name: firebase_messaging + url: "https://pub.dartlang.org" + source: hosted + version: "12.0.2" + firebase_messaging_platform_interface: + dependency: transitive + description: + name: firebase_messaging_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.1" + firebase_messaging_web: + dependency: transitive + description: + name: firebase_messaging_web + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.1" + firebase_storage: + dependency: "direct main" + description: + name: firebase_storage + url: "https://pub.dartlang.org" + source: hosted + version: "10.3.5" + firebase_storage_platform_interface: + dependency: transitive + description: + name: firebase_storage_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.13" + firebase_storage_web: + dependency: transitive + description: + name: firebase_storage_web + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.3" + flare_flutter: + dependency: "direct main" + description: + name: flare_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_blurhash: + dependency: transitive + description: + name: flutter_blurhash + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.0" + flutter_cache_manager: + dependency: "direct main" + description: + name: flutter_cache_manager + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.0" + flutter_form_builder: + dependency: "direct main" + description: + name: flutter_form_builder + url: "https://pub.dartlang.org" + source: hosted + version: "7.5.0" + flutter_image_compress: + dependency: "direct main" + description: + name: flutter_image_compress + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + flutter_launcher_icons: + dependency: "direct main" + description: + name: flutter_launcher_icons + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.0" + flutter_native_splash: + dependency: "direct main" + description: + name: flutter_native_splash + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.7" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.3" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + fluttertoast: + dependency: "direct main" + description: + name: fluttertoast + url: "https://pub.dartlang.org" + source: hosted + version: "8.0.9" + font_awesome_flutter: + dependency: "direct main" + description: + name: font_awesome_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "10.1.0" + get: + dependency: "direct main" + description: + name: get + url: "https://pub.dartlang.org" + source: hosted + version: "4.6.5" + get_storage: + dependency: "direct main" + description: + name: get_storage + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.3" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + html: + dependency: transitive + description: + name: html + url: "https://pub.dartlang.org" + source: hosted + version: "0.15.0" + http: + dependency: transitive + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.13.5" + http_client_helper: + dependency: transitive + description: + name: http_client_helper + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.3" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.1" + image: + dependency: transitive + description: + name: image + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.0" + image_gallery_saver: + dependency: "direct main" + description: + name: image_gallery_saver + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.1" + intl: + dependency: transitive + description: + name: intl + url: "https://pub.dartlang.org" + source: hosted + version: "0.17.0" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.4" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.6.0" + lazy_load_scrollview: + dependency: "direct main" + description: + name: lazy_load_scrollview + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + like_button: + dependency: "direct main" + description: + name: like_button + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + line_icons: + dependency: "direct main" + description: + name: line_icons + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + lint: + dependency: "direct dev" + description: + name: lint + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.4" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.0" + modal_bottom_sheet: + dependency: "direct main" + description: + name: modal_bottom_sheet + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + nested: + dependency: transitive + description: + name: nested + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + octo_image: + dependency: "direct main" + description: + name: octo_image + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.1" + path_drawing: + dependency: transitive + description: + name: path_drawing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + path_provider: + dependency: transitive + description: + name: path_provider + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.11" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.19" + path_provider_ios: + dependency: transitive + description: + name: path_provider_ios + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.11" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.7" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.6" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" + pedantic: + dependency: "direct dev" + description: + name: pedantic + url: "https://pub.dartlang.org" + source: hosted + version: "1.11.1" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.0" + photo_manager: + dependency: transitive + description: + name: photo_manager + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + platform: + dependency: transitive + description: + name: platform + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" + preload_page_view: + dependency: "direct main" + description: + name: preload_page_view + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.6" + process: + dependency: transitive + description: + name: process + url: "https://pub.dartlang.org" + source: hosted + version: "4.2.4" + provider: + dependency: transitive + description: + name: provider + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.3" + readmore: + dependency: "direct main" + description: + name: readmore + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + rxdart: + dependency: transitive + description: + name: rxdart + url: "https://pub.dartlang.org" + source: hosted + version: "0.27.5" + shimmer: + dependency: "direct main" + description: + name: shimmer + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.2" + sqflite: + dependency: transitive + description: + name: sqflite + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.3+1" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.1+1" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + synchronized: + dependency: transitive + description: + name: synchronized + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0+2" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.9" + timeago: + dependency: "direct main" + description: + name: timeago + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.0" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + universal_io: + dependency: transitive + description: + name: universal_io + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.5" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.17" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.17" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.13" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + uuid: + dependency: transitive + description: + name: uuid + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.6" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" + video_player: + dependency: transitive + description: + name: video_player + url: "https://pub.dartlang.org" + source: hosted + version: "2.4.6" + video_player_android: + dependency: transitive + description: + name: video_player_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.9" + video_player_avfoundation: + dependency: transitive + description: + name: video_player_avfoundation + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.5" + video_player_platform_interface: + dependency: transitive + description: + name: video_player_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.4" + video_player_web: + dependency: transitive + description: + name: video_player_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.12" + visibility_detector: + dependency: "direct main" + description: + name: visibility_detector + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.3" + wc_flutter_share: + dependency: "direct main" + description: + name: wc_flutter_share + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.0" + wechat_assets_picker: + dependency: "direct main" + description: + name: wechat_assets_picker + url: "https://pub.dartlang.org" + source: hosted + version: "8.0.0" + win32: + dependency: transitive + description: + name: win32 + url: "https://pub.dartlang.org" + source: hosted + version: "2.7.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0+1" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.0" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.1" +sdks: + dart: ">=2.17.0 <3.0.0" + flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..a77ec82 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,64 @@ +name: meme_baaz +description: Daily Meme Updates. + +publish_to: "none" +version: 1.1.0+110 + +environment: + sdk: ">=2.12.0 <3.0.0" + +dependencies: + animations: ^2.0.3 + cached_network_image: ^3.2.1 + cached_video_player: ^2.0.3 + cloud_firestore: ^3.4.4 + connectivity: ^3.0.6 + cupertino_icons: ^1.0.5 + dio: ^4.0.0 + firebase_auth: ^3.6.3 + firebase_core: ^1.20.1 + firebase_messaging: ^12.0.2 + firebase_storage: ^10.3.5 + flare_flutter: ^3.0.2 + flutter: + sdk: flutter + flutter_cache_manager: ^3.3.0 + flutter_form_builder: ^7.5.0 + flutter_image_compress: ^1.1.1 + flutter_launcher_icons: ^0.10.0 + flutter_native_splash: ^2.2.7 + flutter_svg: ^1.1.3 + fluttertoast: ^8.0.9 + font_awesome_flutter: ^10.1.0 + get: ^4.6.5 + get_storage: ^2.0.3 + google_fonts: ^3.0.1 + image_gallery_saver: ^1.7.1 + lazy_load_scrollview: ^1.3.0 + like_button: ^2.0.4 + line_icons: ^2.0.1 + modal_bottom_sheet: ^2.1.0 + octo_image: ^1.0.2 + preload_page_view: ^0.1.6 + readmore: ^2.2.0 + shimmer: ^2.0.0 + timeago: ^3.3.0 + url_launcher: ^6.1.5 + visibility_detector: ^0.3.3 + wc_flutter_share: ^0.4.0 + wechat_assets_picker: ^8.0.0 + +dev_dependencies: + flutter_test: + sdk: flutter + lint: ^1.5.3 + pedantic: ^1.11.0 + +flutter_native_splash: + image: assets/splash.png + color: "FFFFFF" + +flutter: + uses-material-design: true + assets: + - assets/ diff --git a/test/widget_test.dart b/test/widget_test.dart new file mode 100644 index 0000000..6108afe --- /dev/null +++ b/test/widget_test.dart @@ -0,0 +1,31 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +// ignore: avoid_relative_lib_imports +import '../lib/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +}