├── .gitignore ├── LICENSE ├── README.md ├── slider_menu ├── .idea │ ├── libraries │ │ └── Flutter_Plugins.xml │ ├── modules.xml │ ├── ui_challenge_flutter.iml │ ├── vcs.xml │ └── workspace.xml ├── .metadata ├── analysis_options.yaml ├── android │ ├── .project │ ├── .settings │ │ └── org.eclipse.buildship.core.prefs │ ├── app │ │ ├── .classpath │ │ ├── .project │ │ ├── .settings │ │ │ └── org.eclipse.buildship.core.prefs │ │ ├── build.gradle │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── gen │ │ │ └── cz │ │ │ │ └── stepanzalis │ │ │ │ └── uichallenges │ │ │ │ ├── BuildConfig.java │ │ │ │ ├── Manifest.java │ │ │ │ └── R.java │ │ │ ├── kotlin │ │ │ └── cz │ │ │ │ └── stepanzalis │ │ │ │ └── uichallenges │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── assets │ ├── fonts │ │ └── Roboto-Medium.ttf │ └── images │ │ ├── avatars │ │ ├── avatar1.png │ │ ├── avatar2.png │ │ ├── avatar3.png │ │ ├── avatar4.png │ │ ├── avatar5.png │ │ ├── avatar6.png │ │ ├── avatar7.png │ │ └── user_image.png │ │ ├── ic_back.png │ │ ├── ic_calendar.png │ │ ├── ic_inbox.png │ │ ├── ic_projects_done.png │ │ ├── ic_projects_todo.png │ │ ├── ic_tag.png │ │ ├── ic_trash.png │ │ ├── ic_user.png │ │ └── ic_user_menu.png ├── images │ ├── app.gif │ ├── closed_menu.png │ └── open_menu.png ├── ios │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── Runner-Bridging-Header.h ├── lib │ ├── io │ │ ├── data │ │ │ ├── menu_data.dart │ │ │ ├── person.dart │ │ │ └── persons_data.dart │ │ └── menu_provider.dart │ ├── main.dart │ ├── menu │ │ ├── animated_screen.dart │ │ ├── menu_item.dart │ │ └── menu_screen.dart │ ├── menu_holder.dart │ ├── project │ │ ├── item_person.dart │ │ └── project_screen.dart │ └── theme │ │ └── text_styles.dart ├── pubspec.lock └── pubspec.yaml ├── temp_slider ├── .gitignore ├── .metadata ├── README.md ├── Screenshot 2019-01-11 at 14.25.20.png ├── analysis_options.yaml ├── android │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── temperatureoval │ │ │ │ └── MainActivity.java │ │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── assets │ └── ic_ac.png ├── ios │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── main.m ├── lib │ ├── colors.dart │ ├── main.dart │ ├── type_enum.dart │ └── widgets │ │ ├── central_temp.dart │ │ ├── icon_slider.dart │ │ ├── icon_text.dart │ │ ├── painters │ │ └── ruler_painter.dart │ │ ├── round_button.dart │ │ └── ruler.dart ├── pubspec.yaml ├── screenshot.png └── test │ └── widget_test.dart └── vpn_app ├── README.md ├── android ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── io │ │ │ │ └── flutter │ │ │ │ └── plugins │ │ │ │ └── GeneratedPluginRegistrant.java │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── stepanzalis │ │ │ │ └── vpn_app │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── local.properties ├── settings.gradle └── vpn_app_android.iml ├── assets ├── fonts │ ├── SF-Pro-Display-Bold.otf │ ├── SF-Pro-Display-Medium.otf │ ├── SF-Pro-Display-Regular.otf │ └── SF-Pro-Display-Semibold.otf └── images │ ├── arrow.svg │ ├── check_arrow.svg │ ├── down_arrow.svg │ ├── flags │ ├── australia.svg │ ├── automatic.svg │ ├── india.svg │ ├── russia.svg │ ├── singapore.svg │ ├── sweden.svg │ ├── uk.svg │ └── us.svg │ ├── hamburger.svg │ └── onboarding.png ├── ios ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ ├── Generated.xcconfig │ └── Release.xcconfig ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ └── contents.xcworkspacedata └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── GeneratedPluginRegistrant.h │ ├── GeneratedPluginRegistrant.m │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── io │ └── models │ │ ├── connection_model.dart │ │ ├── server_model.dart │ │ ├── vpn_server.dart │ │ └── welcome_model.dart ├── main.dart ├── ui │ ├── screens │ │ ├── home │ │ │ ├── drawer_layout.dart │ │ │ ├── home_page_screen.dart │ │ │ ├── main_page_container.dart │ │ │ └── widgets │ │ │ │ ├── connection_info_widget.dart │ │ │ │ ├── connection_state_circle_widget.dart │ │ │ │ ├── item_country_server_widget.dart │ │ │ │ ├── rounded_checkbox_widget.dart │ │ │ │ ├── server_container_widget.dart │ │ │ │ └── stroke_circle_widget.dart │ │ └── welcome │ │ │ ├── welcome_screen.dart │ │ │ └── widgets │ │ │ ├── circle_dot.dart │ │ │ └── intro_widget.dart │ └── widgets │ │ └── rounded_button_widget.dart └── util │ ├── colors.dart │ ├── dimens.dart │ ├── router.dart │ ├── status_bar.dart │ ├── string.dart │ └── theme.dart ├── pubspec.yaml ├── screenshots └── screenshot1.png └── test ├── connection_model_tests.dart ├── server_model_tests.dart ├── string_utils_test.dart ├── welcome_model_tests.dart └── widget_tests.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | .DS_Store 6 | /.idea 7 | *.rawproto 8 | *.jar -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Štěpán Záliš 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UI Flutter challenges 2 | 3 | This repository consists of weekly UI challenges from designers at www.dribbble.com. 4 | If anyone wants to see his design live, feel free to send it to: stepan.zalis@gmail.com. 5 | 6 | [![Codemagic build status](https://api.codemagic.io/apps/5c0770552e0492001c5c5782/5c0770552e0492001c5c5781/status_badge.svg)](https://codemagic.io/apps/5c0770552e0492001c5c5782/5c0770552e0492001c5c5781/latest_build) 7 | 8 | Thanks! :v: 9 | 10 | ## Flutter is :blue_heart: 11 | 12 | Feel free to comment and contribute! 13 | 14 | 15 | ### 1. Slide navigation 16 | Design was taken from [Roman Bova](https://dribbble.com/shots/3925867-Activity-Feed-Daily-UI-047-Freebie). Nice and clean slide animation. 17 | 18 | 19 | 20 | ### 2. Thermostat 21 | The goal was to implement the behaviour of scrollable ruler to change a temperature (using a CustomPainter). 22 | 23 | 24 | 25 | ### 3. VPN 26 | Design was taken from freebie [project365](https://project365.design/2018/10/05/day-278-vpn-mobile-app-ui-kit-sketch-freebie/) 27 | 28 | 29 | -------------------------------------------------------------------------------- /slider_menu/.idea/libraries/Flutter_Plugins.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /slider_menu/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /slider_menu/.idea/ui_challenge_flutter.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /slider_menu/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /slider_menu/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: d954ae6850a06ea461d5595cef424e278ed9f17f 8 | channel: dev 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /slider_menu/android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android 4 | Project android created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | -------------------------------------------------------------------------------- /slider_menu/android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir= 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /slider_menu/android/app/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /slider_menu/android/app/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | app 4 | Project app created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /slider_menu/android/app/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir=.. 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /slider_menu/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 27 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "cz.stepanzalis.uichallenges" 42 | minSdkVersion 16 43 | targetSdkVersion 27 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 47 | } 48 | 49 | buildTypes { 50 | release { 51 | // TODO: Add your own signing config for the release build. 52 | // Signing with the debug keys for now, so `flutter run --release` works. 53 | signingConfig signingConfigs.debug 54 | } 55 | } 56 | } 57 | 58 | flutter { 59 | source '../..' 60 | } 61 | 62 | dependencies { 63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 64 | testImplementation 'junit:junit:4.12' 65 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 66 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 67 | } 68 | -------------------------------------------------------------------------------- /slider_menu/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 15 | 19 | 26 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /slider_menu/android/app/src/main/gen/cz/stepanzalis/uichallenges/BuildConfig.java: -------------------------------------------------------------------------------- 1 | /*___Generated_by_IDEA___*/ 2 | 3 | package cz.stepanzalis.uichallenges; 4 | 5 | /* This stub is only used by the IDE. It is NOT the BuildConfig class actually packed into the APK */ 6 | public final class BuildConfig { 7 | public final static boolean DEBUG = Boolean.parseBoolean(null); 8 | } -------------------------------------------------------------------------------- /slider_menu/android/app/src/main/gen/cz/stepanzalis/uichallenges/Manifest.java: -------------------------------------------------------------------------------- 1 | /*___Generated_by_IDEA___*/ 2 | 3 | package cz.stepanzalis.uichallenges; 4 | 5 | /* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */ 6 | public final class Manifest { 7 | } -------------------------------------------------------------------------------- /slider_menu/android/app/src/main/gen/cz/stepanzalis/uichallenges/R.java: -------------------------------------------------------------------------------- 1 | /*___Generated_by_IDEA___*/ 2 | 3 | package cz.stepanzalis.uichallenges; 4 | 5 | /* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */ 6 | public final class R { 7 | } -------------------------------------------------------------------------------- /slider_menu/android/app/src/main/kotlin/cz/stepanzalis/uichallenges/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package cz.stepanzalis.uichallenges 2 | 3 | import android.os.Bundle 4 | 5 | import io.flutter.app.FlutterActivity 6 | import io.flutter.plugins.GeneratedPluginRegistrant 7 | 8 | class MainActivity(): FlutterActivity() { 9 | override fun onCreate(savedInstanceState: Bundle?) { 10 | super.onCreate(savedInstanceState) 11 | GeneratedPluginRegistrant.registerWith(this) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /slider_menu/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /slider_menu/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /slider_menu/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /slider_menu/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /slider_menu/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /slider_menu/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /slider_menu/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /slider_menu/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.2.30' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.1.2' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /slider_menu/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /slider_menu/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 7 | -------------------------------------------------------------------------------- /slider_menu/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /slider_menu/assets/fonts/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/fonts/Roboto-Medium.ttf -------------------------------------------------------------------------------- /slider_menu/assets/images/avatars/avatar1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/avatars/avatar1.png -------------------------------------------------------------------------------- /slider_menu/assets/images/avatars/avatar2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/avatars/avatar2.png -------------------------------------------------------------------------------- /slider_menu/assets/images/avatars/avatar3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/avatars/avatar3.png -------------------------------------------------------------------------------- /slider_menu/assets/images/avatars/avatar4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/avatars/avatar4.png -------------------------------------------------------------------------------- /slider_menu/assets/images/avatars/avatar5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/avatars/avatar5.png -------------------------------------------------------------------------------- /slider_menu/assets/images/avatars/avatar6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/avatars/avatar6.png -------------------------------------------------------------------------------- /slider_menu/assets/images/avatars/avatar7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/avatars/avatar7.png -------------------------------------------------------------------------------- /slider_menu/assets/images/avatars/user_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/avatars/user_image.png -------------------------------------------------------------------------------- /slider_menu/assets/images/ic_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/ic_back.png -------------------------------------------------------------------------------- /slider_menu/assets/images/ic_calendar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/ic_calendar.png -------------------------------------------------------------------------------- /slider_menu/assets/images/ic_inbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/ic_inbox.png -------------------------------------------------------------------------------- /slider_menu/assets/images/ic_projects_done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/ic_projects_done.png -------------------------------------------------------------------------------- /slider_menu/assets/images/ic_projects_todo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/ic_projects_todo.png -------------------------------------------------------------------------------- /slider_menu/assets/images/ic_tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/ic_tag.png -------------------------------------------------------------------------------- /slider_menu/assets/images/ic_trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/ic_trash.png -------------------------------------------------------------------------------- /slider_menu/assets/images/ic_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/ic_user.png -------------------------------------------------------------------------------- /slider_menu/assets/images/ic_user_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/assets/images/ic_user_menu.png -------------------------------------------------------------------------------- /slider_menu/images/app.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/images/app.gif -------------------------------------------------------------------------------- /slider_menu/images/closed_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/images/closed_menu.png -------------------------------------------------------------------------------- /slider_menu/images/open_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/images/open_menu.png -------------------------------------------------------------------------------- /slider_menu/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /slider_menu/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /slider_menu/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /slider_menu/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /slider_menu/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /slider_menu/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /slider_menu/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Original 7 | 8 | 9 | -------------------------------------------------------------------------------- /slider_menu/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/slider_menu/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ui_challenges 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /slider_menu/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /slider_menu/lib/io/data/menu_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:ui_challenges/menu/menu_item.dart'; 2 | 3 | class MenuData { 4 | 5 | final menu = [ 6 | ItemMenu(path: 'assets/images/ic_inbox.png', name: 'Inbox'), 7 | ItemMenu(path: 'assets/images/ic_calendar.png', name: 'Calendar'), 8 | ItemMenu(path: 'assets/images/ic_projects_done.png', name: 'Projects'), 9 | ItemMenu(path: 'assets/images/ic_user.png', name: 'Crew'), 10 | ItemMenu(path: 'assets/images/ic_tag.png', name: 'Tags'), 11 | ItemMenu(path: '', name: ''), 12 | ItemMenu(path: 'assets/images/ic_projects_todo.png', name: 'Projects'), 13 | ]; 14 | } 15 | -------------------------------------------------------------------------------- /slider_menu/lib/io/data/person.dart: -------------------------------------------------------------------------------- 1 | class Person { 2 | 3 | String name; 4 | String imagePath; 5 | String time; 6 | String task; 7 | String state; 8 | 9 | Person(this.name, this.imagePath, this.time, this.state, this.task); 10 | 11 | 12 | } -------------------------------------------------------------------------------- /slider_menu/lib/io/data/persons_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:ui_challenges/io/data/person.dart'; 2 | 3 | class PersonsData { 4 | 5 | final persons = [ 6 | Person('Christian Nelson', 'assets/images/avatars/avatar1.png', 7 | '17 min ago', 'completed', 'Task name'), 8 | Person('Martha Ford', 'assets/images/avatars/avatar2.png', '21 min ago', 9 | 'completed', 'Test'), 10 | Person('Gladys Lawrance', 'assets/images/avatars/avatar3.png', '34 min ago', 11 | 'completed', 'Users'), 12 | Person('Carl Fletcher', 'assets/images/avatars/avatar4.png', '35 min ago', 13 | 'completed', 'Bussiness'), 14 | Person('Dave Roberts', 'assets/images/avatars/avatar5.png', '47 min ago', 15 | 'completed', 'HR rel'), 16 | Person('Hailey Waever', 'assets/images/avatars/avatar6.png', '59 min ago', 17 | 'completed', 'Task to contribute'), 18 | Person('Super Admin', 'assets/images/avatars/avatar7.png', '2 h ago', 19 | 'completed', 'Admin') 20 | ]; 21 | 22 | } -------------------------------------------------------------------------------- /slider_menu/lib/io/menu_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class MenuProvider with ChangeNotifier { 4 | 5 | bool _open = false; 6 | int _selectedId = 0; 7 | 8 | bool get isOpen => _open; 9 | int get getSelected => _selectedId; 10 | 11 | changeSelectedPage(selected) { 12 | _selectedId = selected; 13 | debugPrint(selected.toString()); 14 | } 15 | 16 | toggleMenuPanel() { 17 | _open = !_open; 18 | notifyListeners(); 19 | } 20 | } -------------------------------------------------------------------------------- /slider_menu/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ui_challenges/io/menu_provider.dart'; 3 | import 'package:ui_challenges/menu_holder.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | void main() => runApp(MenuApp(key: ValueKey('menuApp'))); 7 | 8 | class MenuApp extends StatelessWidget { 9 | 10 | const MenuApp({Key key}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) => MaterialApp( 14 | debugShowCheckedModeBanner: false, 15 | theme: Theme.of(context).copyWith( 16 | primaryColor: Colors.white, 17 | accentIconTheme: Theme.of(context).accentIconTheme.copyWith( 18 | color: Colors.white 19 | ) 20 | ), 21 | home: ChangeNotifierProvider( 22 | builder: (_) => MenuProvider(), 23 | child: MenuHolder()) 24 | ); 25 | } -------------------------------------------------------------------------------- /slider_menu/lib/menu/animated_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:provider/provider.dart'; 4 | import 'package:ui_challenges/io/menu_provider.dart'; 5 | import 'package:ui_challenges/theme/text_styles.dart'; 6 | 7 | class AnimatedScreen extends StatefulWidget { 8 | 9 | const AnimatedScreen({@required this.appBarTitle, @required this.body}); 10 | 11 | final String appBarTitle; 12 | final Widget body; 13 | 14 | @override 15 | _AnimatedScreenState createState() => _AnimatedScreenState(); 16 | } 17 | 18 | class _AnimatedScreenState extends State with SingleTickerProviderStateMixin { 19 | 20 | AnimationController _animationController; 21 | Animation _tween; 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | final openPercent = Interval(0.0, 0.8, curve: Curves.easeOut).transform(_tween.value); 26 | 27 | final slideAmount = 255.0 * openPercent; 28 | final contentScale = 1 - (0.35 * openPercent); 29 | 30 | return Consumer( 31 | builder: (context, model, child) { 32 | 33 | if (model.isOpen) _animationController.reverse(); 34 | else _animationController.forward(); 35 | 36 | return Transform( 37 | transform: Matrix4.translationValues(slideAmount, 0.0, 0.0)..scale(contentScale, contentScale), 38 | alignment: Alignment.centerLeft, 39 | child: Container( 40 | decoration: BoxDecoration( 41 | boxShadow: [ 42 | new BoxShadow( 43 | color: Colors.blue[100], 44 | offset: Offset(0.0, 3.0), 45 | blurRadius: 50.0, 46 | spreadRadius: 1.0, 47 | ), 48 | ], 49 | ), 50 | child: Scaffold(appBar: getAppBar(widget.appBarTitle, model), body: widget.body))); 51 | }); 52 | } 53 | 54 | Widget getAppBar(String appBarText, MenuProvider model) => AppBar( 55 | title: Text(appBarText, style: MyTextTheme().getLightSmallGrey().copyWith(fontSize: 20.0)), 56 | leading: IconButton( 57 | icon: Icon(CupertinoIcons.back, color: Colors.grey[400], size: 25.0), 58 | onPressed: () { 59 | model.isOpen ? _animationController.reverse() : _animationController.forward(); 60 | model.toggleMenuPanel(); 61 | }), 62 | elevation: 0.0, 63 | actions: [ 64 | IconButton( 65 | icon: Image(image: AssetImage('assets/images/ic_trash.png'), width: 25, height: 25), 66 | onPressed: () {}, 67 | ) 68 | ], 69 | ); 70 | 71 | @override 72 | void initState() { 73 | _animationController = AnimationController( 74 | duration: Duration(milliseconds: 500), 75 | vsync: this, 76 | )..addListener(() { 77 | setState(() {}); 78 | }); 79 | 80 | _tween = Tween(begin: 0.0, end: 1.0).animate(_animationController); 81 | super.initState(); 82 | } 83 | 84 | @override 85 | void dispose() { 86 | _animationController.dispose(); 87 | super.dispose(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /slider_menu/lib/menu/menu_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ui_challenges/theme/text_styles.dart'; 3 | 4 | class ItemMenu extends StatelessWidget { 5 | 6 | final String path; 7 | final String name; 8 | 9 | const ItemMenu({@required this.path, @required this.name}); 10 | 11 | @override 12 | Widget build(BuildContext context) => Padding( 13 | padding: const EdgeInsets.only(left: 30.0, top: 10.0, bottom: 10.0), 14 | child: Container( 15 | height: 55, 16 | child: Row( 17 | crossAxisAlignment: CrossAxisAlignment.center, 18 | mainAxisAlignment: MainAxisAlignment.start, 19 | textBaseline: TextBaseline.alphabetic, 20 | children: [ 21 | Image.asset(path, width: 25, height: 25, color: Colors.grey[400]), 22 | SizedBox(width: 20.0), 23 | Text(name, 24 | style: MyTextTheme() 25 | .getLightSmallGrey() 26 | .copyWith(fontSize: 22.0, fontWeight: FontWeight.w700)) 27 | ], 28 | ), 29 | ), 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /slider_menu/lib/menu/menu_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ui_challenges/io/data/menu_data.dart'; 3 | import 'package:ui_challenges/menu/menu_item.dart'; 4 | import 'package:ui_challenges/theme/text_styles.dart'; 5 | 6 | class MenuScreen extends StatefulWidget { 7 | 8 | MenuScreen(this.tap); 9 | 10 | Function(int) tap; 11 | 12 | @override 13 | _MenuScreenState createState() => _MenuScreenState(); 14 | } 15 | 16 | class _MenuScreenState extends State { 17 | final data = MenuData().menu; 18 | 19 | @override 20 | Widget build(BuildContext context) => Scaffold( 21 | backgroundColor: Colors.white, 22 | body: SafeArea( 23 | child: Padding( 24 | padding: const EdgeInsets.only(top: 40.0), 25 | child: Column( 26 | children: [ 27 | _AvatarListTile(), 28 | SizedBox(height: 20), 29 | Expanded( 30 | child: ListView.builder( 31 | itemCount: data.length, 32 | itemBuilder: (context, index) { 33 | final model = data[index]; 34 | return GestureDetector( 35 | onTap: () => widget.tap(index), 36 | child: model.path.isEmpty ? _Divider() : ItemMenu(path: model.path, name: model.name)); 37 | }, 38 | )), 39 | ], 40 | ), 41 | ))); 42 | } 43 | 44 | class _Divider extends StatelessWidget { 45 | const _Divider(); 46 | 47 | @override 48 | Widget build(BuildContext context) => Padding( 49 | padding: const EdgeInsets.only(left: 30.0, top: 15, bottom: 15), 50 | child: Container( 51 | height: 2.0, 52 | color: Colors.grey[300], 53 | ), 54 | ); 55 | } 56 | 57 | class _AvatarListTile extends StatelessWidget { 58 | const _AvatarListTile(); 59 | 60 | @override 61 | Widget build(BuildContext context) => ListTile( 62 | leading: 63 | CircleAvatar(radius: 25.0, child: Image.asset('assets/images/avatars/user_image.png', fit: BoxFit.contain)), 64 | title: Text('Roman Bova', style: MyTextTheme().getGrey().copyWith(fontSize: 24, fontWeight: FontWeight.w600)), 65 | subtitle: Text('UI/UX Designer', 66 | style: MyTextTheme().getSmallBlue().copyWith(fontSize: 20, fontWeight: FontWeight.w400))); 67 | } 68 | -------------------------------------------------------------------------------- /slider_menu/lib/menu_holder.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:ui_challenges/io/menu_provider.dart'; 4 | import 'package:ui_challenges/menu/animated_screen.dart'; 5 | import 'package:ui_challenges/menu/menu_screen.dart'; 6 | import 'package:ui_challenges/project/project_screen.dart'; 7 | 8 | class MenuHolder extends StatefulWidget { 9 | const MenuHolder(); 10 | 11 | @override 12 | _MenuHolderState createState() => _MenuHolderState(); 13 | } 14 | 15 | class _MenuHolderState extends State { 16 | 17 | Widget currentScreen = AnimatedScreen(appBarTitle: 'Project', body: ProjectScreen()); 18 | 19 | @override 20 | Widget build(BuildContext context) => Container( 21 | color: Colors.white, 22 | child: Stack( 23 | children: [ 24 | MenuScreen((selectedId) => { 25 | Provider.of(context, listen: false).changeSelectedPage(selectedId), 26 | Provider.of(context, listen: false).toggleMenuPanel() 27 | }), 28 | currentScreen 29 | ], 30 | ), 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /slider_menu/lib/project/item_person.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ui_challenges/io/data/person.dart'; 3 | import 'package:ui_challenges/theme/text_styles.dart'; 4 | 5 | class ItemPerson extends StatelessWidget { 6 | ItemPerson(this.person); 7 | 8 | final Person person; 9 | final MyTextTheme textTheme = MyTextTheme(); 10 | 11 | @override 12 | Widget build(BuildContext context) => PersonListTile(person, textTheme); 13 | } 14 | 15 | class PersonListTile extends ListTile { 16 | 17 | final Person person; 18 | final MyTextTheme textTheme; 19 | const PersonListTile(this.person, this.textTheme); 20 | 21 | @override 22 | Widget build(BuildContext context) => Padding( 23 | padding: const EdgeInsets.only(left: 20.0), 24 | child: Row(mainAxisAlignment: MainAxisAlignment.start, children: [ 25 | _AvatarWidget(person.imagePath, 40.0), 26 | SizedBox(width: 20), 27 | Expanded( 28 | child: Column( 29 | crossAxisAlignment: CrossAxisAlignment.start, 30 | children: [_FirstRowInPerson(person, textTheme), _SecondRowInPerson(person, textTheme)])), 31 | ]), 32 | ); 33 | } 34 | 35 | 36 | class _AvatarWidget extends StatelessWidget { 37 | 38 | final String path; 39 | final double radius; 40 | 41 | const _AvatarWidget(this.path, this.radius) 42 | : assert(path != null), 43 | assert(radius != null); 44 | 45 | @override 46 | Widget build(BuildContext context) => Material( 47 | shape: CircleBorder(), 48 | color: Colors.transparent, 49 | shadowColor: Colors.transparent, 50 | child: Image.asset(path, width: radius, height: radius)); 51 | } 52 | 53 | class _FirstRowInPerson extends StatelessWidget { 54 | final Person person; 55 | final MyTextTheme textTheme; 56 | 57 | const _FirstRowInPerson(this.person, this.textTheme) 58 | : assert(person != null), 59 | assert(textTheme != null); 60 | 61 | @override 62 | Widget build(BuildContext context) => Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ 63 | Text(person.name, style: textTheme.getGrey()), 64 | Padding( 65 | padding: EdgeInsets.only(right: 10.0), 66 | child: Text(person.time, 67 | style: textTheme.getLightSmallGrey().copyWith(fontSize: 17.0, fontWeight: FontWeight.w600))) 68 | ]); 69 | } 70 | 71 | class _SecondRowInPerson extends StatelessWidget { 72 | final Person person; 73 | final MyTextTheme textTheme; 74 | 75 | const _SecondRowInPerson(this.person, this.textTheme) 76 | : assert(person != null), 77 | assert(textTheme != null); 78 | 79 | @override 80 | Widget build(BuildContext context) => Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ 81 | Text(person.state, style: textTheme.getLightSmallGrey()), 82 | SizedBox(width: 15.0), 83 | Text(person.task, style: textTheme.getSmallBlue()) 84 | ]); 85 | } 86 | -------------------------------------------------------------------------------- /slider_menu/lib/project/project_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:ui_challenges/io/data/persons_data.dart'; 4 | import 'package:ui_challenges/project/item_person.dart'; 5 | import 'package:ui_challenges/theme/text_styles.dart'; 6 | 7 | class ProjectScreen extends StatelessWidget { 8 | 9 | PersonsData data; 10 | 11 | ProjectScreen() { 12 | data = PersonsData(); 13 | } 14 | 15 | @override 16 | Widget build(BuildContext context) => _ActivityListView(data); 17 | } 18 | 19 | class _ActivityListView extends StatelessWidget { 20 | 21 | final PersonsData data; 22 | const _ActivityListView(this.data); 23 | 24 | @override 25 | Widget build(BuildContext context) => Container( 26 | color: Colors.white, 27 | child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ 28 | Padding( 29 | padding: EdgeInsets.only(left: 20.0, top: 20.0), 30 | child: Text("Activity Feed", 31 | style: MyTextTheme().getSmallBlue().copyWith(fontWeight: FontWeight.bold, fontSize: 25))), 32 | Expanded( 33 | child: ListView.builder( 34 | padding: EdgeInsets.only(top: 20), 35 | itemCount: data.persons.length, 36 | itemBuilder: (context, int index) => 37 | Padding(padding: EdgeInsets.only(top: 20.0, bottom: 20.0), child: ItemPerson(data.persons[index])))) 38 | ])); 39 | } 40 | -------------------------------------------------------------------------------- /slider_menu/lib/theme/text_styles.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class MyTextTheme { 4 | 5 | const MyTextTheme(); 6 | 7 | TextStyle getSmallBlue() { 8 | return _getSmallFont(Colors.blue); 9 | } 10 | 11 | TextStyle getBigBlue() { 12 | return getSmallBlue().copyWith(fontSize: 25, fontWeight: FontWeight.bold); 13 | } 14 | 15 | TextStyle getLightSmallGrey() { 16 | return _getSmallFont(Colors.grey[400]); 17 | } 18 | 19 | TextStyle getGrey() { 20 | return TextStyle(fontSize: 22.0, color: Colors.blueGrey[300], fontWeight: FontWeight.w600); 21 | } 22 | 23 | _getSmallFont(Color color) { 24 | return TextStyle(fontSize: 15.0, color: color); 25 | } 26 | 27 | 28 | } -------------------------------------------------------------------------------- /slider_menu/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: ui_challenges 2 | description: UI Challenges Flutter 3 | 4 | version: 1.0.0+1 5 | 6 | environment: 7 | sdk: ">=2.2.3 <3.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | # State management 14 | provider: ^3.0.0+1 15 | 16 | cupertino_icons: ^0.1.2 17 | 18 | dev_dependencies: 19 | flutter_test: 20 | sdk: flutter 21 | 22 | flutter: 23 | uses-material-design: true 24 | 25 | assets: 26 | - assets/images/avatars/avatar1.png 27 | - assets/images/avatars/avatar2.png 28 | - assets/images/avatars/avatar3.png 29 | - assets/images/avatars/avatar4.png 30 | - assets/images/avatars/avatar5.png 31 | - assets/images/avatars/avatar6.png 32 | - assets/images/avatars/avatar7.png 33 | - assets/images/avatars/user_image.png 34 | 35 | - assets/images/ic_user.png 36 | - assets/images/ic_back.png 37 | - assets/images/ic_trash.png 38 | 39 | - assets/images/ic_inbox.png 40 | - assets/images/ic_projects_todo.png 41 | - assets/images/ic_projects_done.png 42 | - assets/images/ic_calendar.png 43 | - assets/images/ic_tag.png 44 | 45 | 46 | fonts: 47 | - family: Roboto 48 | fonts: 49 | - asset: assets/fonts/Roboto-Medium.ttf 50 | 51 | -------------------------------------------------------------------------------- /temp_slider/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.lock 4 | *.log 5 | *.pyc 6 | *.swp 7 | .DS_Store 8 | .atom/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # Visual Studio Code related 20 | .vscode/ 21 | 22 | # Flutter/Dart/Pub related 23 | **/doc/api/ 24 | .dart_tool/ 25 | .flutter-plugins 26 | .packages 27 | .pub-cache/ 28 | .pub/ 29 | build/ 30 | 31 | # Android related 32 | **/android/**/gradle-wrapper.jar 33 | **/android/.gradle 34 | **/android/captures/ 35 | **/android/gradlew 36 | **/android/gradlew.bat 37 | **/android/local.properties 38 | **/android/**/GeneratedPluginRegistrant.java 39 | 40 | # iOS/XCode related 41 | **/ios/**/*.mode1v3 42 | **/ios/**/*.mode2v3 43 | **/ios/**/*.moved-aside 44 | **/ios/**/*.pbxuser 45 | **/ios/**/*.perspectivev3 46 | **/ios/**/*sync/ 47 | **/ios/**/.sconsign.dblite 48 | **/ios/**/.tags* 49 | **/ios/**/.vagrant/ 50 | **/ios/**/DerivedData/ 51 | **/ios/**/Icon? 52 | **/ios/**/Pods/ 53 | **/ios/**/.symlinks/ 54 | **/ios/**/profile 55 | **/ios/**/xcuserdata 56 | **/ios/.generated/ 57 | **/ios/Flutter/App.framework 58 | **/ios/Flutter/Flutter.framework 59 | **/ios/Flutter/Generated.xcconfig 60 | **/ios/Flutter/app.flx 61 | **/ios/Flutter/app.zip 62 | **/ios/Flutter/flutter_assets/ 63 | **/ios/ServiceDefinitions.json 64 | **/ios/Runner/GeneratedPluginRegistrant.* 65 | 66 | # Exceptions to above rules. 67 | !**/ios/**/default.mode1v3 68 | !**/ios/**/default.mode2v3 69 | !**/ios/**/default.pbxuser 70 | !**/ios/**/default.perspectivev3 71 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 72 | -------------------------------------------------------------------------------- /temp_slider/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 1407091bfb5bb535630d4d596541817737da8412 8 | channel: dev 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /temp_slider/README.md: -------------------------------------------------------------------------------- 1 | # Smart Home App 2 | 3 | Original design from https://dribbble.com/shakuro 4 | Project page: https://dribbble.com/shots/5534531-Smart-Home-App-Thermostat 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /temp_slider/Screenshot 2019-01-11 at 14.25.20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/Screenshot 2019-01-11 at 14.25.20.png -------------------------------------------------------------------------------- /temp_slider/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 27 29 | 30 | lintOptions { 31 | disable 'InvalidPackage' 32 | } 33 | 34 | defaultConfig { 35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 36 | applicationId "com.example.temperatureoval" 37 | minSdkVersion 16 38 | targetSdkVersion 27 39 | versionCode flutterVersionCode.toInteger() 40 | versionName flutterVersionName 41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | testImplementation 'junit:junit:4.12' 59 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 61 | } 62 | -------------------------------------------------------------------------------- /temp_slider/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 15 | 19 | 26 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /temp_slider/android/app/src/main/java/com/example/temperatureoval/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.temperatureoval; 2 | 3 | import android.os.Bundle; 4 | import io.flutter.app.FlutterActivity; 5 | import io.flutter.plugins.GeneratedPluginRegistrant; 6 | 7 | public class MainActivity extends FlutterActivity { 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | GeneratedPluginRegistrant.registerWith(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /temp_slider/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /temp_slider/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /temp_slider/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /temp_slider/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /temp_slider/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /temp_slider/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /temp_slider/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /temp_slider/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.2.1' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | jcenter() 16 | } 17 | } 18 | 19 | rootProject.buildDir = '../build' 20 | subprojects { 21 | project.buildDir = "${rootProject.buildDir}/${project.name}" 22 | } 23 | subprojects { 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /temp_slider/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /temp_slider/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /temp_slider/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /temp_slider/assets/ic_ac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/assets/ic_ac.png -------------------------------------------------------------------------------- /temp_slider/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /temp_slider/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /temp_slider/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /temp_slider/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /temp_slider/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /temp_slider/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /temp_slider/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /temp_slider/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Original 7 | 8 | 9 | -------------------------------------------------------------------------------- /temp_slider/ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /temp_slider/ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /temp_slider/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | temperature_oval 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /temp_slider/ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /temp_slider/lib/colors.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | 4 | Color pinkColor = Color.fromARGB(255, 224, 0, 71); 5 | Color greyColor = Color.fromARGB(255, 76, 75, 75); 6 | Color backgroundColor = Color.fromARGB(255, 19, 17, 20); 7 | Color rulerColor = Color.fromARGB(220, 76, 75, 75); 8 | -------------------------------------------------------------------------------- /temp_slider/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:temperature_oval/type_enum.dart'; 3 | import 'package:temperature_oval/widgets/central_temp.dart'; 4 | import 'package:temperature_oval/widgets/icon_slider.dart'; 5 | import 'package:temperature_oval/widgets/icon_text.dart'; 6 | import 'package:temperature_oval/widgets/round_button.dart'; 7 | import 'package:temperature_oval/widgets/ruler.dart'; 8 | import 'colors.dart'; 9 | 10 | void main() => runApp(MyApp()); 11 | 12 | class MyApp extends StatelessWidget { 13 | @override 14 | Widget build(BuildContext context) => MaterialApp( 15 | debugShowCheckedModeBanner: false, 16 | home: HomePage(), 17 | ); 18 | } 19 | 20 | class HomePage extends StatefulWidget { 21 | const HomePage({Key key}) : super(key: key); 22 | 23 | @override 24 | HomePageState createState() => new HomePageState(); 25 | } 26 | 27 | class HomePageState extends State { 28 | double value = 3; 29 | num temp = 77; 30 | List sampleData = []; 31 | 32 | @override 33 | Widget build(BuildContext context) => Scaffold( 34 | appBar: AppBar( 35 | elevation: 0, 36 | backgroundColor: backgroundColor, 37 | leading: Icon(Icons.arrow_back), 38 | ), 39 | body: Container( 40 | color: backgroundColor, 41 | width: MediaQuery.of(context).size.width, 42 | height: MediaQuery.of(context).size.height, 43 | child: SafeArea( 44 | child: Stack( 45 | children: [ 46 | Positioned( 47 | top: MediaQuery.of(context).size.height / 4, 48 | left: 0, 49 | child: CentralTemp(temperature: temp.toString())), 50 | Positioned(top: 30, left: MediaQuery.of(context).size.width / 1.3, child: RulerWidget(size: MediaQuery.of(context).size, function: setTemp)), 51 | Positioned( 52 | left: 30, 53 | top: MediaQuery.of(context).size.height / 1.9, 54 | child: IconTextWidget( 55 | icon: Icons.alarm, 56 | text: 'Set smart schedule', 57 | type: IconText.greyIconPinkText)), 58 | Positioned( 59 | left: 30, 60 | top: MediaQuery.of(context).size.height / 1.7, 61 | child: 62 | Container(height: 80, child: Row(children: sampleData))), 63 | Positioned( 64 | left: 30, 65 | top: MediaQuery.of(context).size.height / 1.4, 66 | child: IconSlider()), 67 | Positioned( 68 | child: Align( 69 | alignment: FractionalOffset.bottomCenter, 70 | child: IconTextWidget( 71 | icon: Icons.power_settings_new, 72 | text: 'Hold to turn off', 73 | type: IconText.pinkIconGreyText))) 74 | ], 75 | ), 76 | ), 77 | )); 78 | 79 | setTemp(temp) { 80 | setState(() { 81 | this.temp = temp.round(); 82 | }); 83 | } 84 | 85 | @override 86 | void initState() { 87 | sampleData.add(RoundButton(icon: Icons.ac_unit)); 88 | sampleData.add(SizedBox(width: 15)); 89 | sampleData.add(RoundButton(icon: Icons.place)); 90 | sampleData.add(SizedBox(width: 15)); 91 | sampleData.add(RoundButton(icon: Icons.wb_sunny)); 92 | 93 | super.initState(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /temp_slider/lib/type_enum.dart: -------------------------------------------------------------------------------- 1 | 2 | enum IconText { 3 | pinkIconGreyText, greyIconPinkText 4 | } 5 | -------------------------------------------------------------------------------- /temp_slider/lib/widgets/central_temp.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CentralTemp extends StatelessWidget { 4 | 5 | const CentralTemp({Key key, this.temperature}) : super(key: key); 6 | 7 | // actul temperature number 8 | final temperature; 9 | 10 | @override 11 | Widget build(BuildContext context) => Padding( 12 | padding: const EdgeInsets.only(left: 20.0), 13 | child: Column( 14 | mainAxisAlignment: MainAxisAlignment.start, 15 | crossAxisAlignment: CrossAxisAlignment.start, 16 | mainAxisSize: MainAxisSize.min, 17 | children: [ 18 | Text('TEMPERATURE, °F', 19 | style: TextStyle(fontSize: 13, color: Colors.white)), 20 | Text(temperature, 21 | style: TextStyle(fontSize: 160, color: Colors.white, height: 0.85)), 22 | ], 23 | ), 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /temp_slider/lib/widgets/icon_slider.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:temperature_oval/colors.dart'; 5 | 6 | class IconSlider extends StatefulWidget { 7 | const IconSlider({ 8 | Key key, 9 | }) : super(key: key); 10 | 11 | @override 12 | IconSliderState createState() => new IconSliderState(); 13 | } 14 | 15 | class IconSliderState extends State with TickerProviderStateMixin { 16 | var sliderValue = 3.0; 17 | 18 | AnimationController _animationController; 19 | 20 | @override 21 | Widget build(BuildContext context) => Row( 22 | mainAxisAlignment: MainAxisAlignment.center, 23 | crossAxisAlignment: CrossAxisAlignment.center, 24 | children: [ 25 | Container( 26 | child: AnimatedBuilder( 27 | animation: _animationController, 28 | child: ImageIcon(AssetImage('assets/ic_ac.png'), 29 | color: greyColor, size: 20.0), 30 | builder: (context, widget) => Transform.rotate( 31 | angle: _animationController.value * pi, child: widget), 32 | ), 33 | ), 34 | Container( 35 | width: MediaQuery.of(context).size.width / 1.3, 36 | child: Slider( 37 | value: sliderValue, 38 | min: 0, 39 | max: 10, 40 | onChanged: (double newValue) { 41 | setState(() { 42 | sliderValue = newValue; 43 | _animationController.forward(); 44 | 45 | _animationController.addStatusListener((status) { 46 | if (status == AnimationStatus.completed) { 47 | _animationController.value = 0; 48 | } 49 | }); 50 | }); 51 | }, 52 | activeColor: pinkColor, 53 | inactiveColor: greyColor), 54 | ) 55 | ], 56 | ); 57 | 58 | @override 59 | void initState() { 60 | _animationController = new AnimationController( 61 | duration: const Duration(milliseconds: 800), 62 | vsync: this, 63 | )..addListener(() { 64 | setState(() {}); 65 | }); 66 | 67 | super.initState(); 68 | } 69 | 70 | @override 71 | void dispose() { 72 | _animationController.dispose(); 73 | super.dispose(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /temp_slider/lib/widgets/icon_text.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:temperature_oval/colors.dart'; 3 | import 'package:temperature_oval/type_enum.dart'; 4 | 5 | class IconTextWidget extends StatelessWidget { 6 | 7 | const IconTextWidget({Key key, this.icon, this.text, this.type}) 8 | : super(key: key); 9 | 10 | final icon; 11 | final text; 12 | final type; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | final iconColor = type == IconText.greyIconPinkText ? greyColor : pinkColor; 17 | final textColor = type == IconText.greyIconPinkText ? pinkColor : greyColor; 18 | 19 | return Row(mainAxisAlignment: MainAxisAlignment.center, children: [ 20 | Icon(icon, color: iconColor), 21 | SizedBox(width: 7), 22 | Text(text, style: TextStyle(fontSize: 13, color: textColor)) 23 | ]); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /temp_slider/lib/widgets/painters/ruler_painter.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:temperature_oval/colors.dart'; 5 | 6 | class RulerPainter extends CustomPainter { 7 | final smallLength = 25.0; 8 | final longLength = 15.0; 9 | final numberOfLines = 200; 10 | 11 | final strokeWidth = 1.0; 12 | 13 | final Paint rulerPaint; 14 | 15 | RulerPainter({Key key, this.scrollLen}) : rulerPaint = new Paint() { 16 | rulerPaint.color = rulerColor; 17 | } 18 | 19 | final double scrollLen; 20 | 21 | @override 22 | void paint(Canvas canvas, Size size) { 23 | var tickMarkLength; 24 | final angle = 2 * pi / numberOfLines; 25 | 26 | final radius = size.width; 27 | canvas.save(); 28 | 29 | final circlePaint = Paint() 30 | ..style = PaintingStyle.stroke 31 | ..strokeWidth = 5.0 32 | ..color = pinkColor; 33 | 34 | final shadow = Paint() 35 | ..style = PaintingStyle.stroke 36 | ..strokeWidth = 10.0 37 | ..color = pinkColor 38 | ..maskFilter = MaskFilter.blur(BlurStyle.normal, 90); 39 | 40 | // pink border around ruler 41 | canvas.drawCircle(new Offset(radius, radius), radius + 8, circlePaint); 42 | canvas.drawCircle(new Offset(radius, radius), radius + 8, shadow); 43 | 44 | // drawing 45 | canvas.translate(radius, radius); 46 | 47 | for (var i = 0; i < numberOfLines; i++) { 48 | tickMarkLength = i % 5 == 0 ? smallLength : longLength; 49 | rulerPaint.strokeWidth = strokeWidth; 50 | canvas.drawLine(new Offset(0.0, -radius), 51 | new Offset(0.0, -radius + tickMarkLength), rulerPaint); 52 | 53 | canvas.rotate(angle); 54 | } 55 | canvas.restore(); 56 | } 57 | 58 | @override 59 | bool shouldRepaint(RulerPainter oldDelegate) => true; 60 | } 61 | -------------------------------------------------------------------------------- /temp_slider/lib/widgets/round_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:temperature_oval/colors.dart'; 3 | 4 | class RoundButton extends StatefulWidget { 5 | RoundButton({Key key, this.icon}) : super(key: key); 6 | 7 | final icon; 8 | bool tapped = false; 9 | 10 | @override 11 | _RoundButtonState createState() => _RoundButtonState(); 12 | } 13 | 14 | class _RoundButtonState extends State { 15 | @override 16 | Widget build(BuildContext context) => GestureDetector( 17 | onTap: handleSelected, 18 | child: Material( 19 | color: Colors.transparent, 20 | child: Container( 21 | decoration: BoxDecoration( 22 | border: Border.all( 23 | color: widget.tapped ? pinkColor : greyColor, width: 2.0), 24 | color: widget.tapped ? pinkColor : Colors.transparent, 25 | shape: BoxShape.circle, 26 | ), 27 | child: Padding( 28 | padding: EdgeInsets.all(15.0), 29 | child: Icon( 30 | widget.icon, 31 | size: 25.0, 32 | color: widget.tapped ? Colors.white : greyColor, 33 | ), 34 | ), 35 | ), 36 | )); 37 | 38 | handleSelected() { 39 | setState(() { 40 | widget.tapped = !widget.tapped; 41 | }); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /temp_slider/lib/widgets/ruler.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:temperature_oval/widgets/painters/ruler_painter.dart'; 3 | 4 | class RulerWidget extends StatefulWidget { 5 | 6 | RulerWidget({ 7 | Key key, 8 | this.size, 9 | this.function, 10 | }) : super(key: key); 11 | 12 | Size size; 13 | Function(double) function; 14 | 15 | @override 16 | RulerWidgetState createState() => new RulerWidgetState(); 17 | } 18 | 19 | class RulerWidgetState extends State { 20 | double _y = 0; 21 | double _len = 0; 22 | 23 | GlobalKey keyPaint = GlobalKey(); 24 | 25 | @override 26 | Widget build(BuildContext context) => GestureDetector( 27 | onVerticalDragStart: (detail) { 28 | _y = detail.globalPosition.dy; 29 | }, 30 | onVerticalDragUpdate: (detail) { 31 | setState(() { 32 | _len += detail.globalPosition.dy - _y; 33 | _y = detail.globalPosition.dy; 34 | widget.function(_len); 35 | }); 36 | }, 37 | child: Transform( 38 | transform: Matrix4.rotationZ(_len / 10), 39 | alignment: FractionalOffset.centerRight, 40 | child: Container( 41 | height: 400, 42 | width: 200, 43 | child: CustomPaint( 44 | willChange: true, 45 | painter: RulerPainter(scrollLen: _len), 46 | ), 47 | ), 48 | ), 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /temp_slider/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: temperature_oval 2 | description: A new Flutter project. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # Read more about versioning at semver.org. 10 | version: 1.0.0+1 11 | 12 | environment: 13 | sdk: ">=2.1.0 <3.0.0" 14 | 15 | dependencies: 16 | flutter: 17 | sdk: flutter 18 | 19 | # The following adds the Cupertino Icons font to your application. 20 | # Use with the CupertinoIcons class for iOS style icons. 21 | cupertino_icons: ^0.1.2 22 | 23 | dev_dependencies: 24 | flutter_test: 25 | sdk: flutter 26 | 27 | 28 | # For information on the generic Dart part of this file, see the 29 | # following page: https://www.dartlang.org/tools/pub/pubspec 30 | 31 | # The following section is specific to Flutter. 32 | flutter: 33 | 34 | # The following line ensures that the Material Icons font is 35 | # included with your application, so that you can use the icons in 36 | # the material Icons class. 37 | uses-material-design: true 38 | 39 | # To add assets to your application, add an assets section, like this: 40 | assets: 41 | - assets/ic_ac.png 42 | 43 | 44 | # An image asset can refer to one or more resolution-specific "variants", see 45 | # https://flutter.io/assets-and-images/#resolution-aware. 46 | 47 | # For details regarding adding assets from package dependencies, see 48 | # https://flutter.io/assets-and-images/#from-packages 49 | 50 | # To add custom fonts to your application, add a fonts section here, 51 | # in this "flutter" section. Each entry in this list should have a 52 | # "family" key with the font family name, and a "fonts" key with a 53 | # list giving the asset and other descriptors for the font. For 54 | # example: 55 | # fonts: 56 | # - family: Schyler 57 | # fonts: 58 | # - asset: fonts/Schyler-Regular.ttf 59 | # - asset: fonts/Schyler-Italic.ttf 60 | # style: italic 61 | # - family: Trajan Pro 62 | # fonts: 63 | # - asset: fonts/TrajanPro.ttf 64 | # - asset: fonts/TrajanPro_Bold.ttf 65 | # weight: 700 66 | # 67 | # For details regarding fonts from package dependencies, 68 | # see https://flutter.io/custom-fonts/#from-packages 69 | -------------------------------------------------------------------------------- /temp_slider/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/temp_slider/screenshot.png -------------------------------------------------------------------------------- /temp_slider/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:temperature_oval/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /vpn_app/README.md: -------------------------------------------------------------------------------- 1 | # 📶 VPN App 2 | 3 | Flutter UI challenge (3.) 4 | 5 | ### State Managment 6 | - Provider 7 | 8 | ### Dependencies 9 | - flutter_svg 10 | -------------------------------------------------------------------------------- /vpn_app/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 4 | 5 | android { 6 | compileSdkVersion 28 7 | 8 | sourceSets { 9 | main.java.srcDirs += 'src/main/kotlin' 10 | } 11 | 12 | lintOptions { 13 | disable 'InvalidPackage' 14 | } 15 | 16 | defaultConfig { 17 | applicationId "com.stepanzalis.vpn_app" 18 | minSdkVersion 19 19 | targetSdkVersion 28 20 | versionCode 1 21 | versionName "0.0.1" 22 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 23 | } 24 | 25 | buildTypes { 26 | release { 27 | // TODO: Add your own signing config for the release build. 28 | // Signing with the debug keys for now, so `flutter run --release` works. 29 | signingConfig signingConfigs.debug 30 | } 31 | } 32 | } 33 | 34 | flutter { 35 | source '../..' 36 | } 37 | 38 | dependencies { 39 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 40 | testImplementation 'junit:junit:4.12' 41 | androidTestImplementation 'androidx.test:runner:1.1.1' 42 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 43 | } 44 | -------------------------------------------------------------------------------- /vpn_app/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /vpn_app/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 13 | 20 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /vpn_app/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java: -------------------------------------------------------------------------------- 1 | package io.flutter.plugins; 2 | 3 | import io.flutter.plugin.common.PluginRegistry; 4 | 5 | /** 6 | * Generated file. Do not edit. 7 | */ 8 | public final class GeneratedPluginRegistrant { 9 | public static void registerWith(PluginRegistry registry) { 10 | if (alreadyRegisteredWith(registry)) { 11 | return; 12 | } 13 | } 14 | 15 | private static boolean alreadyRegisteredWith(PluginRegistry registry) { 16 | final String key = GeneratedPluginRegistrant.class.getCanonicalName(); 17 | if (registry.hasPlugin(key)) { 18 | return true; 19 | } 20 | registry.registrarFor(key); 21 | return false; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /vpn_app/android/app/src/main/kotlin/com/stepanzalis/vpn_app/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.stepanzalis.vpn_app 2 | 3 | import android.os.Bundle 4 | 5 | import io.flutter.app.FlutterActivity 6 | import io.flutter.plugins.GeneratedPluginRegistrant 7 | 8 | class MainActivity: FlutterActivity() { 9 | override fun onCreate(savedInstanceState: Bundle?) { 10 | super.onCreate(savedInstanceState) 11 | GeneratedPluginRegistrant.registerWith(this) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /vpn_app/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /vpn_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /vpn_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /vpn_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /vpn_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /vpn_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /vpn_app/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /vpn_app/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /vpn_app/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.2.71' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.2.1' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /vpn_app/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /vpn_app/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 6 | -------------------------------------------------------------------------------- /vpn_app/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /vpn_app/android/local.properties: -------------------------------------------------------------------------------- 1 | sdk.dir=/Users/stepanzalis/Library/Android/sdk 2 | flutter.sdk=/Users/stepanzalis/flutter 3 | flutter.buildMode=release 4 | flutter.versionName=1.0.0 5 | flutter.versionCode=1 -------------------------------------------------------------------------------- /vpn_app/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /vpn_app/android/vpn_app_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /vpn_app/assets/fonts/SF-Pro-Display-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/assets/fonts/SF-Pro-Display-Bold.otf -------------------------------------------------------------------------------- /vpn_app/assets/fonts/SF-Pro-Display-Medium.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/assets/fonts/SF-Pro-Display-Medium.otf -------------------------------------------------------------------------------- /vpn_app/assets/fonts/SF-Pro-Display-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/assets/fonts/SF-Pro-Display-Regular.otf -------------------------------------------------------------------------------- /vpn_app/assets/fonts/SF-Pro-Display-Semibold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/assets/fonts/SF-Pro-Display-Semibold.otf -------------------------------------------------------------------------------- /vpn_app/assets/images/arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /vpn_app/assets/images/check_arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /vpn_app/assets/images/down_arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /vpn_app/assets/images/flags/australia.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /vpn_app/assets/images/flags/automatic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /vpn_app/assets/images/flags/india.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /vpn_app/assets/images/flags/russia.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /vpn_app/assets/images/flags/singapore.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /vpn_app/assets/images/flags/sweden.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /vpn_app/assets/images/flags/uk.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /vpn_app/assets/images/flags/us.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /vpn_app/assets/images/hamburger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /vpn_app/assets/images/onboarding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/assets/images/onboarding.png -------------------------------------------------------------------------------- /vpn_app/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /vpn_app/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /vpn_app/ios/Flutter/Generated.xcconfig: -------------------------------------------------------------------------------- 1 | // This is a generated file; do not edit or check into version control. 2 | FLUTTER_ROOT=/Users/stepanzalis/flutter 3 | FLUTTER_APPLICATION_PATH=/Users/stepanzalis/Desktop/vpn_app 4 | FLUTTER_TARGET=lib/main.dart 5 | FLUTTER_BUILD_DIR=build 6 | SYMROOT=${SOURCE_ROOT}/../build/ios 7 | FLUTTER_FRAMEWORK_DIR=/Users/stepanzalis/flutter/bin/cache/artifacts/engine/ios 8 | FLUTTER_BUILD_NAME=1.0.0 9 | FLUTTER_BUILD_NUMBER=1 10 | -------------------------------------------------------------------------------- /vpn_app/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /vpn_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /vpn_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /vpn_app/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /vpn_app/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /vpn_app/ios/Runner/GeneratedPluginRegistrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | #ifndef GeneratedPluginRegistrant_h 6 | #define GeneratedPluginRegistrant_h 7 | 8 | #import 9 | 10 | @interface GeneratedPluginRegistrant : NSObject 11 | + (void)registerWithRegistry:(NSObject*)registry; 12 | @end 13 | 14 | #endif /* GeneratedPluginRegistrant_h */ 15 | -------------------------------------------------------------------------------- /vpn_app/ios/Runner/GeneratedPluginRegistrant.m: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | #import "GeneratedPluginRegistrant.h" 6 | 7 | @implementation GeneratedPluginRegistrant 8 | 9 | + (void)registerWithRegistry:(NSObject*)registry { 10 | } 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | vpn_app 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /vpn_app/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /vpn_app/lib/io/models/connection_model.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class ConnectionModel with ChangeNotifier { 5 | 6 | bool _connected = false; 7 | bool get isConnected => _connected; 8 | 9 | String get connectionStateTitle => isConnected ? 'CONNECTED' : 'DISCONNECTED'; 10 | String get buttonTitle => isConnected ? 'DISCONNECT' : 'CONNECT NOW'; 11 | 12 | void changeConnectionState() { 13 | _connected = !_connected; 14 | notifyListeners(); 15 | } 16 | } -------------------------------------------------------------------------------- /vpn_app/lib/io/models/server_model.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:vpn_app/io/models/vpn_server.dart'; 4 | 5 | class ServerModel with ChangeNotifier { 6 | 7 | VpnServer _selectedServer = servers[1]; 8 | 9 | int get selectedIndex => _selectedServer.index; 10 | VpnServer get selectedServer => _selectedServer; 11 | 12 | void changeServer(int index) { 13 | if (index < 0 || index > servers.length - 1) return null; 14 | 15 | _selectedServer = servers[index]; 16 | notifyListeners(); 17 | } 18 | 19 | static final servers = [ 20 | VpnServer('Automatic', 'us.svg', 0), 21 | VpnServer('New York, NY', 'us.svg', 1), 22 | VpnServer('London', 'uk.svg', 2), 23 | VpnServer('Moscow', 'russia.svg', 3), 24 | VpnServer('Stockholm', 'sweden.svg', 4), 25 | VpnServer('Melbourne', 'australia.svg', 5), 26 | VpnServer('New Deplhi', 'india.svg', 6), 27 | VpnServer('Singapore', 'india.svg', 7), 28 | ]; 29 | } -------------------------------------------------------------------------------- /vpn_app/lib/io/models/vpn_server.dart: -------------------------------------------------------------------------------- 1 | class VpnServer { 2 | 3 | final String stateName; 4 | final String flagAssetName; 5 | final int index; 6 | 7 | VpnServer(this.stateName, this.flagAssetName, this.index) 8 | : assert(stateName != null || stateName.isNotEmpty, 'Country name should not be empty'), 9 | assert(flagAssetName != null, 'Flag resource should not be null'); 10 | } 11 | -------------------------------------------------------------------------------- /vpn_app/lib/io/models/welcome_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:vpn_app/ui/screens/welcome/widgets/intro_widget.dart'; 3 | 4 | class WelcomeModel with ChangeNotifier { 5 | 6 | int _currentIndex = 0; 7 | int get currentIndex => _currentIndex; 8 | 9 | List get widgets => _introWidgetList; 10 | int get widgetLength => widgets.length; 11 | 12 | bool get lastPage => _currentIndex == widgetLength - 1; 13 | 14 | void changeCurrentIndex(int index) { 15 | if (index < 0 || index > widgetLength - 1) return null; 16 | 17 | _currentIndex = index; 18 | notifyListeners(); 19 | } 20 | 21 | final List _introWidgetList = [ 22 | IntroWidget( 23 | title: 'Secured, forever.', 24 | imageRes: 'assets/images/onboarding.png', 25 | description: 26 | 'Curabitur lobortis id lorem id bibendum. Ut id consectetur magna. Quisque volutpat augue enim, pulvinar lobortis.'), 27 | IntroWidget( 28 | title: 'Secured, forever.', 29 | imageRes: 'assets/images/onboarding.png', 30 | description: 31 | 'Curabitur lobortis id lorem id bibendum. Ut id consectetur magna. Quisque volutpat augue enim, pulvinar lobortis.'), 32 | IntroWidget( 33 | title: 'Secured, forever.', 34 | imageRes: 'assets/images/onboarding.png', 35 | description: 36 | 'Curabitur lobortis id lorem id bibendum. Ut id consectetur magna. Quisque volutpat augue enim, pulvinar lobortis.'), 37 | ]; 38 | } 39 | -------------------------------------------------------------------------------- /vpn_app/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:vpn_app/io/models/connection_model.dart'; 4 | import 'package:vpn_app/io/models/welcome_model.dart'; 5 | import 'package:vpn_app/io/models/server_model.dart'; 6 | import 'package:vpn_app/ui/screens/home/home_page_screen.dart'; 7 | import 'package:vpn_app/util/router.dart'; 8 | import 'package:vpn_app/util/status_bar.dart'; 9 | import 'package:vpn_app/util/theme.dart'; 10 | 11 | Future main() async { 12 | setPreferredOrientations(); 13 | setStatusBarColor(); 14 | runApp(VpnApp()); 15 | } 16 | 17 | class VpnApp extends StatelessWidget { 18 | 19 | @override 20 | Widget build(BuildContext context) => MultiProvider( 21 | providers: [ 22 | ChangeNotifierProvider(builder: (context) => WelcomeModel()), 23 | ChangeNotifierProvider(builder: (context) => ConnectionModel()), 24 | ChangeNotifierProvider(builder: (context) => ServerModel()), 25 | ], 26 | child: Directionality( 27 | textDirection: TextDirection.ltr, 28 | child: MaterialApp( 29 | title: 'VPN', 30 | debugShowCheckedModeBanner: false, 31 | theme: appTheme, 32 | onGenerateRoute: Router.generateRoute, 33 | home: HomeScreen(), 34 | ), 35 | ), 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /vpn_app/lib/ui/screens/home/drawer_layout.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DrawerLayout extends StatelessWidget { 4 | 5 | const DrawerLayout(); 6 | 7 | @override 8 | Widget build(BuildContext context) => Drawer( 9 | child: Container( 10 | color: Colors.white, 11 | child: Center( 12 | child: Text('Implement me', style: Theme.of(context).textTheme.body2), 13 | ), 14 | ), 15 | ); 16 | } -------------------------------------------------------------------------------- /vpn_app/lib/ui/screens/home/home_page_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_svg/svg.dart'; 3 | import 'package:vpn_app/ui/screens/home/drawer_layout.dart'; 4 | import 'package:vpn_app/ui/screens/home/main_page_container.dart'; 5 | 6 | class HomeScreen extends StatelessWidget { 7 | 8 | const HomeScreen(); 9 | 10 | @override 11 | Widget build(BuildContext context) => SafeArea( 12 | child: Scaffold( 13 | appBar: AppBar( 14 | elevation: 0, 15 | backgroundColor: Theme.of(context).backgroundColor, 16 | leading: Builder( 17 | builder: (context) => IconButton( 18 | icon: SvgPicture.asset('assets/images/hamburger.svg'), 19 | onPressed: () => Scaffold.of(context).openDrawer(), 20 | ), 21 | ), 22 | centerTitle: true, 23 | title: Text( 24 | 'VPN', 25 | style: Theme.of(context).textTheme.title, 26 | ), 27 | ), 28 | drawer: DrawerLayout(), 29 | body: MainPageContainer()), 30 | ); 31 | } -------------------------------------------------------------------------------- /vpn_app/lib/ui/screens/home/main_page_container.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:vpn_app/io/models/connection_model.dart'; 4 | import 'package:vpn_app/io/models/server_model.dart'; 5 | import 'package:vpn_app/io/models/vpn_server.dart'; 6 | import 'package:vpn_app/ui/screens/home/widgets/connection_info_widget.dart'; 7 | import 'package:vpn_app/ui/screens/home/widgets/connection_state_circle_widget.dart'; 8 | import 'package:vpn_app/ui/screens/home/widgets/server_container_widget.dart'; 9 | import 'package:vpn_app/ui/widgets/rounded_button_widget.dart'; 10 | import 'package:vpn_app/util/dimens.dart'; 11 | 12 | class MainPageContainer extends StatelessWidget { 13 | const MainPageContainer(); 14 | 15 | @override 16 | Widget build(BuildContext context) => Container( 17 | width: double.infinity, 18 | height: double.infinity, 19 | color: Theme.of(context).backgroundColor, 20 | child: Stack( 21 | alignment: Alignment.center, 22 | children: [ 23 | Column( 24 | mainAxisSize: MainAxisSize.min, 25 | mainAxisAlignment: MainAxisAlignment.center, 26 | crossAxisAlignment: CrossAxisAlignment.center, 27 | children: [ 28 | _ConnectionStateInfo(), 29 | SizedBox(height: separatorHeight), 30 | _ConnectionStateCircle(), 31 | SizedBox(height: separatorHeight), 32 | _ConnectionButton(), 33 | ], 34 | ), 35 | _ServerBottomContainer() 36 | ], 37 | ), 38 | ); 39 | } 40 | 41 | class _ConnectionStateCircle extends StatelessWidget { 42 | const _ConnectionStateCircle(); 43 | 44 | @override 45 | Widget build(BuildContext context) => Consumer( 46 | builder: (context, model, child) => ConnectionStateCircleWidget( 47 | circleSize: connectionCircleSize, 48 | connected: model.isConnected, 49 | ), 50 | ); 51 | } 52 | 53 | class _ConnectionButton extends StatelessWidget { 54 | const _ConnectionButton(); 55 | 56 | @override 57 | Widget build(BuildContext context) => Consumer( 58 | builder: (context, model, child) => RoundedButton( 59 | title: model.buttonTitle, 60 | filled: model.isConnected, 61 | onTap: () => model.changeConnectionState(), 62 | ), 63 | ); 64 | } 65 | 66 | class _ConnectionStateInfo extends StatelessWidget { 67 | const _ConnectionStateInfo(); 68 | 69 | @override 70 | Widget build(BuildContext context) => Consumer( 71 | builder: (context, model, child) => ConnectionStateInfo( 72 | title: model.connectionStateTitle, 73 | connected: model.isConnected, 74 | ), 75 | ); 76 | } 77 | 78 | class _ServerBottomContainer extends StatelessWidget { 79 | const _ServerBottomContainer(); 80 | 81 | @override 82 | Widget build(BuildContext context) { 83 | final VpnServer selectedServer = Provider.of(context).selectedServer; 84 | 85 | return Align( 86 | alignment: Alignment.bottomCenter, 87 | child: ServerContainer(chosenServer: selectedServer), 88 | ); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /vpn_app/lib/ui/screens/home/widgets/connection_info_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:vpn_app/util/colors.dart'; 3 | import 'package:vpn_app/util/dimens.dart'; 4 | import 'package:vpn_app/util/string.dart'; 5 | 6 | class ConnectionStateInfo extends StatelessWidget { 7 | 8 | final String title; 9 | final bool connected; 10 | 11 | const ConnectionStateInfo({@required this.title, @required this.connected}); 12 | 13 | @override 14 | Widget build(BuildContext context) => Material( 15 | elevation: 8, 16 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(40)), 17 | child: Container( 18 | height: connectionStateHeight, 19 | width: connectionStateWidth, 20 | decoration: BoxDecoration( 21 | color: Colors.white, 22 | borderRadius: BorderRadius.circular(30.0), 23 | ), 24 | child: Row( 25 | mainAxisSize: MainAxisSize.min, 26 | mainAxisAlignment: MainAxisAlignment.center, 27 | crossAxisAlignment: CrossAxisAlignment.center, 28 | children: [ 29 | Text(capitalize(title.toLowerCase()), style: Theme.of(context).textTheme.overline), 30 | SizedBox(width: 10), 31 | _ConnectionIcon(connected: connected), 32 | ], 33 | ), 34 | ), 35 | ); 36 | } 37 | 38 | class _ConnectionIcon extends StatelessWidget { 39 | final double size = 10; 40 | final bool connected; 41 | 42 | const _ConnectionIcon({@required this.connected}); 43 | 44 | @override 45 | Widget build(BuildContext context) => Container( 46 | width: size, 47 | height: size, 48 | decoration: BoxDecoration( 49 | color: connected ? connectedStateColor : disconnectedStateColor, 50 | shape: BoxShape.circle, 51 | ), 52 | ); 53 | } 54 | -------------------------------------------------------------------------------- /vpn_app/lib/ui/screens/home/widgets/connection_state_circle_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_svg/flutter_svg.dart'; 4 | import 'package:vpn_app/ui/screens/home/widgets/stroke_circle_widget.dart'; 5 | import 'package:vpn_app/util/colors.dart'; 6 | import 'package:vpn_app/util/dimens.dart'; 7 | 8 | class ConnectionStateCircleWidget extends StatelessWidget { 9 | final double circleSize; 10 | final bool connected; 11 | 12 | const ConnectionStateCircleWidget({this.circleSize = 200, @required this.connected}) 13 | : assert(circleSize >= 0, '$ConnectionStateCircleWidget must be bigger then zero'); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | final Color outerCircleColor = connected ? primaryColor : outerDisconnectedColor; 18 | final Color innerCircleColor = connected ? innerConnectedColor : innerDisconnectedColor; 19 | 20 | return Stack( 21 | alignment: Alignment.center, 22 | children: [ 23 | StrokedCircle(circleSize: circleSize, color: outerCircleColor), 24 | StrokedCircle(circleSize: outerCircleSize, color: innerCircleColor), 25 | _InnerIconCircle(circleSize: innerCircleSize, connected: connected), 26 | ], 27 | ); 28 | } 29 | } 30 | 31 | class _IconWidget extends StatelessWidget { 32 | final String imagePath; 33 | final double size; 34 | 35 | const _IconWidget({@required this.imagePath, this.size = 30, Key key}) : super(key: key); 36 | 37 | @override 38 | Widget build(BuildContext context) => SvgPicture.asset( 39 | imagePath, 40 | width: size, 41 | height: size, 42 | ); 43 | } 44 | 45 | class _InnerIconCircle extends StatelessWidget { 46 | final bool connected; 47 | final double circleSize; 48 | 49 | _InnerIconCircle({@required this.connected, this.circleSize = 160}); 50 | 51 | @override 52 | Widget build(BuildContext context) { 53 | final List gradientColors = connected ? connectedGradientColors : disconnectedGradientColors; 54 | final CrossFadeState currentFadeState = connected ? CrossFadeState.showSecond : CrossFadeState.showFirst; 55 | 56 | return Container( 57 | width: circleSize, 58 | height: circleSize, 59 | decoration: BoxDecoration( 60 | shape: BoxShape.circle, 61 | gradient: LinearGradient( 62 | begin: Alignment.bottomLeft, 63 | end: Alignment.topRight, 64 | colors: gradientColors, 65 | ), 66 | ), 67 | child: Center( 68 | child: AnimatedCrossFade( 69 | duration: Duration(milliseconds: 300), 70 | firstChild: _IconWidget(imagePath: 'assets/images/arrow.svg', key: UniqueKey()), 71 | secondChild: _IconWidget(imagePath: 'assets/images/check_arrow.svg', key: UniqueKey()), 72 | crossFadeState: currentFadeState, 73 | ), 74 | ), 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /vpn_app/lib/ui/screens/home/widgets/item_country_server_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_svg/flutter_svg.dart'; 3 | import 'package:vpn_app/io/models/vpn_server.dart'; 4 | import 'package:vpn_app/ui/screens/home/widgets/rounded_checkbox_widget.dart'; 5 | import 'package:vpn_app/util/dimens.dart'; 6 | 7 | class CountryServerItem extends StatelessWidget { 8 | final VpnServer server; 9 | final bool selected; 10 | 11 | const CountryServerItem({@required this.server, this.selected}); 12 | 13 | @override 14 | Widget build(BuildContext context) => Container( 15 | width: double.infinity, 16 | height: itemStateFlagHeight, 17 | color: Theme.of(context).backgroundColor, 18 | child: Row( 19 | mainAxisSize: MainAxisSize.max, 20 | crossAxisAlignment: CrossAxisAlignment.center, 21 | children: [ 22 | Expanded( 23 | flex: 2, 24 | child: SvgPicture.asset('assets/images/flags/${server.flagAssetName}'), 25 | ), 26 | Expanded( 27 | flex: 5, 28 | child: Text( 29 | '${server.stateName}', 30 | style: Theme.of(context).textTheme.body1.copyWith(fontSize: 18), 31 | ), 32 | ), 33 | Expanded( 34 | flex: 3, 35 | child: RoundedCheckbox(checked: selected), 36 | ) 37 | ], 38 | ), 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /vpn_app/lib/ui/screens/home/widgets/rounded_checkbox_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:vpn_app/util/colors.dart'; 3 | import 'package:vpn_app/util/dimens.dart'; 4 | 5 | class RoundedCheckbox extends StatelessWidget { 6 | final double size; 7 | final bool checked; 8 | 9 | const RoundedCheckbox({@required this.checked, this.size}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | final Color color = checked ? primaryColor : Colors.white; 14 | final Color borderColor = checked ? primaryColor : strokeCheckBoxColor; 15 | 16 | return Container( 17 | width: size ?? checkBoxHeight, 18 | height: size ?? checkBoxHeight, 19 | decoration: BoxDecoration( 20 | border: Border.all(color: borderColor, width: 1), 21 | color: color, 22 | shape: BoxShape.circle, 23 | ), 24 | child: checked 25 | ? Icon( 26 | Icons.check, 27 | size: 15, 28 | color: Colors.white, 29 | ) 30 | : null, 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /vpn_app/lib/ui/screens/home/widgets/server_container_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_svg/flutter_svg.dart'; 3 | import 'package:provider/provider.dart'; 4 | import 'package:vpn_app/io/models/server_model.dart'; 5 | import 'package:vpn_app/io/models/vpn_server.dart'; 6 | import 'package:vpn_app/ui/screens/home/widgets/item_country_server_widget.dart'; 7 | import 'package:vpn_app/util/colors.dart'; 8 | 9 | class ServerContainer extends StatelessWidget { 10 | 11 | final VpnServer chosenServer; 12 | const ServerContainer({@required this.chosenServer}); 13 | 14 | @override 15 | Widget build(BuildContext context) => GestureDetector( 16 | onTap: () => _openServerList(context), 17 | child: _ContainerHolder( 18 | child: Consumer( 19 | builder: (context, model, child) => Row( 20 | mainAxisAlignment: MainAxisAlignment.center, 21 | crossAxisAlignment: CrossAxisAlignment.center, 22 | children: [ 23 | SvgPicture.asset('assets/images/flags/${chosenServer.flagAssetName}', width: 20, height: 20), 24 | SizedBox(width: 15), 25 | Text( 26 | '${chosenServer.stateName}', 27 | style: Theme.of(context).textTheme.body1.copyWith(color: primaryTextColor), 28 | ), 29 | SizedBox(width: 10), 30 | child, 31 | ], 32 | ), 33 | child: SvgPicture.asset('assets/images/down_arrow.svg', width: 8, height: 8), 34 | ), 35 | ), 36 | ); 37 | } 38 | 39 | _openServerList(context) { 40 | final List servers = ServerModel.servers; 41 | 42 | showModalBottomSheet( 43 | backgroundColor: Theme.of(context).backgroundColor, 44 | context: context, 45 | builder: (context) => Consumer( 46 | builder: (context, model, child) => Container( 47 | margin: EdgeInsets.only(top: 20), 48 | child: Column( 49 | children: [ 50 | child, 51 | SizedBox(height: 20), 52 | Expanded( 53 | child: ListView.builder( 54 | itemCount: servers.length, 55 | itemBuilder: (context, index) => GestureDetector( 56 | onTap: () { 57 | model.changeServer(index); 58 | Navigator.of(context).pop(); 59 | }, 60 | child: CountryServerItem( 61 | server: servers[index], 62 | selected: model.selectedIndex == index, 63 | ), 64 | ), 65 | ), 66 | ), 67 | ], 68 | ), 69 | ), 70 | child: Center(child: Text('Pick your server', style: Theme.of(context).textTheme.overline)), 71 | ), 72 | ); 73 | } 74 | 75 | class _ContainerHolder extends StatelessWidget { 76 | 77 | final Widget child; 78 | const _ContainerHolder({@required this.child}); 79 | 80 | @override 81 | Widget build(BuildContext context) => Container( 82 | height: 70, 83 | decoration: BoxDecoration( 84 | color: Colors.white, 85 | boxShadow: [ 86 | BoxShadow( 87 | color: Colors.grey[300], 88 | blurRadius: 5.0, 89 | ), 90 | ], 91 | ), 92 | child: child, 93 | ); 94 | } 95 | -------------------------------------------------------------------------------- /vpn_app/lib/ui/screens/home/widgets/stroke_circle_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:vpn_app/util/dimens.dart'; 3 | 4 | class StrokedCircle extends StatelessWidget { 5 | final Color color; 6 | final double circleSize; 7 | 8 | StrokedCircle({@required this.color, this.circleSize = 100, Key key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) => Container( 12 | width: circleSize, 13 | height: circleSize, 14 | decoration: BoxDecoration( 15 | shape: BoxShape.circle, 16 | color: color, 17 | ), 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /vpn_app/lib/ui/screens/welcome/welcome_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:vpn_app/io/models/welcome_model.dart'; 4 | import 'package:vpn_app/ui/screens/welcome/widgets/circle_dot.dart'; 5 | import 'package:vpn_app/ui/widgets/rounded_button_widget.dart'; 6 | import 'package:vpn_app/util/router.dart'; 7 | 8 | class WelcomeScreen extends StatelessWidget { 9 | @override 10 | Widget build(BuildContext context) => SafeArea( 11 | child: Scaffold( 12 | body: Container( 13 | child: Stack( 14 | children: [ 15 | _OnboardingPageView(), 16 | _PageCircleBar(), 17 | _GetStartedButton(), 18 | ], 19 | ), 20 | ), 21 | ), 22 | ); 23 | } 24 | 25 | class _OnboardingPageView extends StatelessWidget { 26 | 27 | const _OnboardingPageView(); 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | final model = Provider.of(context, listen: false); 32 | 33 | return PageView.builder( 34 | physics: ClampingScrollPhysics(), 35 | onPageChanged: (index) => _onPageChanged(index, model), 36 | itemCount: model.widgetLength, 37 | itemBuilder: (context, index) => model.widgets[index]); 38 | } 39 | 40 | _onPageChanged(index, WelcomeModel model) => model.changeCurrentIndex(index); 41 | } 42 | 43 | class _PageCircleBar extends StatelessWidget { 44 | 45 | const _PageCircleBar(); 46 | 47 | @override 48 | Widget build(BuildContext context) => Consumer( 49 | builder: (context, model, child) => Padding( 50 | padding: const EdgeInsets.only(bottom: 110.0), 51 | child: Align( 52 | alignment: Alignment.bottomCenter, 53 | child: Container( 54 | color: Theme.of(context).backgroundColor, 55 | child: Row( 56 | mainAxisSize: MainAxisSize.min, 57 | mainAxisAlignment: MainAxisAlignment.center, 58 | children: [ 59 | for (int i = 0; i < model.widgetLength; i++) ...[ 60 | CircleDot(selected: i == model.currentIndex, key: UniqueKey()) 61 | ] 62 | ], 63 | ), 64 | ), 65 | ), 66 | ), 67 | ); 68 | } 69 | 70 | class _GetStartedButton extends StatelessWidget { 71 | 72 | const _GetStartedButton(); 73 | 74 | @override 75 | Widget build(BuildContext context) { 76 | final WelcomeModel model = Provider.of(context); 77 | final double opacity = model.lastPage ? 1 : 0; 78 | 79 | return AnimatedOpacity( 80 | opacity: opacity, 81 | duration: Duration(milliseconds: 200), 82 | curve: Curves.easeIn, 83 | child: Align( 84 | alignment: Alignment.bottomCenter, 85 | child: Padding( 86 | padding: EdgeInsets.only(bottom: 30), 87 | child: RoundedButton( 88 | title: 'GET STARTED', 89 | onTap: () => Navigator.of(context).pushNamed(Router.HOME_PAGE), 90 | ), 91 | ), 92 | ), 93 | ); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /vpn_app/lib/ui/screens/welcome/widgets/circle_dot.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:vpn_app/util/colors.dart'; 3 | 4 | class CircleDot extends StatelessWidget { 5 | final bool selected; 6 | 7 | CircleDot({@required this.selected, Key key}) : super(key: key); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | final double size = selected ? 10 : 8; 12 | final Color color = selected ? unselectedGrey : selectedGrey; 13 | 14 | return AnimatedContainer( 15 | margin: EdgeInsets.symmetric(horizontal: 5), 16 | width: size, 17 | height: size, 18 | duration: Duration(milliseconds: 200), 19 | decoration: BoxDecoration( 20 | color: color, 21 | shape: BoxShape.circle, 22 | ), 23 | ); 24 | } 25 | } -------------------------------------------------------------------------------- /vpn_app/lib/ui/screens/welcome/widgets/intro_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class IntroWidget extends StatelessWidget { 4 | 5 | final String title; 6 | final String description; 7 | final String imageRes; 8 | 9 | IntroWidget({@required this.title, @required this.description, this.imageRes, Key key}) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Container( 14 | color: Theme.of(context).backgroundColor, 15 | child: Column( 16 | crossAxisAlignment: CrossAxisAlignment.center, 17 | children: [ 18 | SizedBox(height: 50), 19 | Image.asset(imageRes, scale: 1.2), 20 | SizedBox(height: 20), 21 | Text(title, style: Theme.of(context).textTheme.headline), 22 | Padding( 23 | padding: EdgeInsets.fromLTRB(30, 10, 30, 0), 24 | child: Text(description, style: Theme.of(context).textTheme.overline, textAlign: TextAlign.center)) 25 | ], 26 | )); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /vpn_app/lib/ui/widgets/rounded_button_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:vpn_app/util/colors.dart'; 3 | import 'package:vpn_app/util/dimens.dart'; 4 | 5 | class RoundedButton extends StatelessWidget { 6 | 7 | final String title; 8 | final bool filled; 9 | final Function onTap; 10 | 11 | const RoundedButton({@required this.title, this.filled = true, this.onTap}); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | final Color backgroundColor = filled ? primaryColor : Colors.white; 16 | final Color borderSideColor = filled ? primaryColor : disconnectedButtonColor; 17 | 18 | return MaterialButton( 19 | height: primaryButtonHeight, 20 | padding: EdgeInsets.only(left: 40, right: 40), 21 | color: backgroundColor, 22 | onPressed: onTap, 23 | elevation: 2, 24 | child: Text( 25 | title, 26 | style: filled 27 | ? Theme.of(context).textTheme.button 28 | : Theme.of(context).textTheme.button.copyWith(color: disconnectedTextColor), 29 | ), 30 | shape: RoundedRectangleBorder( 31 | side: BorderSide(color: borderSideColor), 32 | borderRadius: BorderRadius.circular(40), 33 | ), 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /vpn_app/lib/util/colors.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// General 4 | const Color backgroundColor = Colors.white; 5 | const Color primaryColor = Color(0xFF0094fc); 6 | 7 | const Color primaryTextColor = Color(0xFF011f3f); 8 | const Color secondaryTextColor = Color(0xFF8b959a); 9 | 10 | const Color selectedGrey = Color(0x48919ba0); 11 | const Color unselectedGrey = Color(0xFF919ba0); 12 | 13 | /// widgets 14 | final Color strokeCheckBoxColor = Colors.grey[300]; 15 | 16 | // connection state button 17 | const Color connectedStateColor = Color(0xFF5ed40a); 18 | const Color disconnectedStateColor = Color(0xFFcecece); 19 | 20 | // connection button 21 | const Color disconnectedButtonColor = Color(0xFF5B5B5B); 22 | const Color disconnectedTextColor = Color(0xFF011F3F); 23 | 24 | // circle widget 25 | const outerDisconnectedColor = Color(0xFF53585C); 26 | const innerConnectedColor = Color(0xFF0260B1); 27 | const innerDisconnectedColor = Color(0xFF777B7F); 28 | 29 | const List connectedGradientColors = [ 30 | Color(0xFF2861ff), 31 | Color(0xFF25b5ff), 32 | ]; 33 | 34 | const List disconnectedGradientColors = [ 35 | Color(0xFFc2cded), 36 | Color(0xFFa2a3a4), 37 | ]; 38 | 39 | -------------------------------------------------------------------------------- /vpn_app/lib/util/dimens.dart: -------------------------------------------------------------------------------- 1 | 2 | // widgets sizes 3 | const double connectionCircleSize = 200; 4 | const double outerCircleSize = 180; 5 | const double innerCircleSize = 160; 6 | 7 | const double connectionStateHeight = 45; 8 | const double connectionStateWidth = 160; 9 | const double checkBoxHeight = 22; 10 | const double itemStateFlagHeight = 50; 11 | 12 | // buttons 13 | const double primaryButtonHeight = 50; 14 | 15 | // separator (others) 16 | const double separatorHeight = 30; 17 | const double strokeWidth = 10; 18 | 19 | -------------------------------------------------------------------------------- /vpn_app/lib/util/router.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:vpn_app/ui/screens/home/home_page_screen.dart'; 3 | import 'package:vpn_app/ui/screens/welcome/welcome_screen.dart'; 4 | 5 | class Router { 6 | 7 | static const HOME_PAGE = "/home"; 8 | static const DEFAULT = "/"; 9 | 10 | static Route generateRoute(RouteSettings settings) { 11 | switch (settings.name) { 12 | case DEFAULT: 13 | return MaterialPageRoute(builder: (_) => WelcomeScreen()); 14 | case HOME_PAGE: 15 | return MaterialPageRoute(builder: (_) => HomeScreen()); 16 | default: 17 | return MaterialPageRoute( 18 | builder: (_) => Scaffold(body: Center(child: Text('No route defined for ${settings.name}')))); 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /vpn_app/lib/util/status_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | 4 | void setStatusBarColor() { 5 | SystemChrome.setSystemUIOverlayStyle( 6 | SystemUiOverlayStyle( 7 | statusBarIconBrightness: Brightness.dark, 8 | systemNavigationBarColor: Colors.white, 9 | statusBarColor: Colors.white, 10 | ), 11 | ); 12 | } 13 | 14 | Future setPreferredOrientations() async { 15 | await SystemChrome.setPreferredOrientations( 16 | [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown], 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /vpn_app/lib/util/string.dart: -------------------------------------------------------------------------------- 1 | String capitalize(String s) => s[0].toUpperCase() + s.substring(1); 2 | -------------------------------------------------------------------------------- /vpn_app/lib/util/theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:vpn_app/util/colors.dart'; 3 | 4 | var appTheme = ThemeData( 5 | brightness: Brightness.light, 6 | backgroundColor: backgroundColor, 7 | primaryColor: primaryColor, 8 | fontFamily: 'SF-Pro-Display-Medium', 9 | buttonTheme: ButtonThemeData( 10 | buttonColor: primaryColor 11 | ), 12 | textTheme: TextTheme( 13 | title: TextStyle(color: primaryTextColor, fontSize: 20.0), // App bar 14 | headline: TextStyle(color: primaryTextColor, fontSize: 20.0, fontFamily: 'SF-Pro-Display', fontWeight: FontWeight.w800), // Onboarding title 15 | body1: TextStyle(color: primaryTextColor, fontSize: 18.0, fontFamily: 'SF-Pro-Display-Regular'), // regular text 16 | overline: TextStyle(color: secondaryTextColor, fontSize: 14.0, letterSpacing: 0), // description text 17 | button: TextStyle(color: Colors.white, fontSize: 14.0, fontWeight: FontWeight.bold, fontFamily: 'SF-Pro-Display-Bold',letterSpacing: 1), 18 | ), 19 | ); 20 | -------------------------------------------------------------------------------- /vpn_app/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: vpn_app 2 | description: Flutter UI challenge 3 | 4 | version: 1.0.0+1 5 | 6 | environment: 7 | sdk: ">=2.2.2 <3.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | cupertino_icons: ^0.1.2 13 | provider: ^3.1.0 14 | flutter_svg: ^0.14.0 15 | 16 | dev_dependencies: 17 | test: 18 | flutter_test: 19 | sdk: flutter 20 | 21 | flutter: 22 | uses-material-design: true 23 | 24 | 25 | assets: 26 | - assets/images/ 27 | - assets/images/flags/ 28 | 29 | fonts: 30 | - family: SF-Pro-Display 31 | fonts: 32 | - asset: assets/fonts/SF-Pro-Display-Bold.otf 33 | - asset: assets/fonts/SF-Pro-Display-Medium.otf 34 | - asset: assets/fonts/SF-Pro-Display-Regular.otf 35 | - asset: assets/fonts/SF-Pro-Display-Semibold.otf 36 | 37 | -------------------------------------------------------------------------------- /vpn_app/screenshots/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanzalis/ui_challenge_flutter/08c1574abf715f45ff9ff888732ae4617a762a18/vpn_app/screenshots/screenshot1.png -------------------------------------------------------------------------------- /vpn_app/test/connection_model_tests.dart: -------------------------------------------------------------------------------- 1 | import 'package:test/test.dart'; 2 | import 'package:vpn_app/io/models/connection_model.dart'; 3 | 4 | void main() { 5 | group('Connection tests', () { 6 | 7 | test('connection state should ba false when init', () { 8 | final ConnectionModel model = ConnectionModel(); 9 | expect(model.isConnected, false); 10 | }); 11 | 12 | test('connection state must be changed when method to change is call', () { 13 | final ConnectionModel model = ConnectionModel(); 14 | model.changeConnectionState(); 15 | expect(model.isConnected, true); 16 | }); 17 | 18 | test('connection state must be changed when method to change is call', () { 19 | final ConnectionModel model = ConnectionModel(); 20 | model.changeConnectionState(); 21 | expect(model.isConnected, true); 22 | }); 23 | }); 24 | } -------------------------------------------------------------------------------- /vpn_app/test/server_model_tests.dart: -------------------------------------------------------------------------------- 1 | import 'package:test/test.dart'; 2 | import 'package:vpn_app/io/models/server_model.dart'; 3 | 4 | void main() { 5 | group('Server tests', () { 6 | 7 | test('server with index 1 should be selected at init', () { 8 | final ServerModel model = ServerModel(); 9 | expect(model.selectedIndex, 1); 10 | }); 11 | 12 | test('index of selected server should be changed when method is call', () { 13 | final ServerModel model = ServerModel(); 14 | final int valueToTest = 10; 15 | 16 | model.changeServer(valueToTest); 17 | expect(model.selectedIndex, 1); 18 | }); 19 | }); 20 | } -------------------------------------------------------------------------------- /vpn_app/test/string_utils_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:test/test.dart'; 2 | import 'package:vpn_app/util/string.dart'; 3 | 4 | void main() { 5 | test('capitalize function should return string with first letter uppercased', () { 6 | 7 | final String normalText = "test"; 8 | final String upperCasedText = capitalize(normalText); 9 | 10 | expect(upperCasedText, "Test"); 11 | }); 12 | } -------------------------------------------------------------------------------- /vpn_app/test/welcome_model_tests.dart: -------------------------------------------------------------------------------- 1 | import 'package:test/test.dart'; 2 | import 'package:vpn_app/io/models/welcome_model.dart'; 3 | 4 | void main() { 5 | group('Welcome tests', () { 6 | 7 | test('current index should be 0 at start', () { 8 | final WelcomeModel model = WelcomeModel(); 9 | expect(model.currentIndex, 0); 10 | }); 11 | 12 | test('vvalid value should be changed', () { 13 | final WelcomeModel model = WelcomeModel(); 14 | final int valueToTest = 2; 15 | 16 | model.changeCurrentIndex(valueToTest); 17 | expect(model.currentIndex, valueToTest); 18 | }); 19 | 20 | test('intro widgets length should be the same as length of the widget array', () { 21 | final WelcomeModel model = WelcomeModel(); 22 | 23 | final int expectedLength = model.widgets.length; 24 | expect(model.widgetLength, expectedLength); 25 | }); 26 | 27 | test('Last page should reflect array size minus one', () { 28 | final WelcomeModel model = WelcomeModel(); 29 | 30 | final int lastPageIndex = model.widgetLength - 1; 31 | model.changeCurrentIndex(lastPageIndex); 32 | expect(model.currentIndex, lastPageIndex); 33 | }); 34 | 35 | test('Change index to non existing value does not do anything', () { 36 | final WelcomeModel model = WelcomeModel(); 37 | 38 | final int highRandomValue = model.widgetLength + 1000; 39 | model.changeCurrentIndex(highRandomValue); 40 | expect(model.currentIndex, 0); 41 | }); 42 | 43 | test('Change index to non to negative value does not do anything', () { 44 | final WelcomeModel model = WelcomeModel(); 45 | 46 | final int negativeValue = -1; 47 | model.changeCurrentIndex(negativeValue); 48 | expect(model.currentIndex, 0); 49 | }); 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /vpn_app/test/widget_tests.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | 3 | import 'package:vpn_app/main.dart'; 4 | 5 | void main() { 6 | testWidgets('smoke test', (WidgetTester tester) async { 7 | await tester.pumpWidget(VpnApp()); 8 | }); 9 | } 10 | --------------------------------------------------------------------------------