├── ios ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ └── project.pbxproj ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist └── .gitignore ├── web ├── favicon.png ├── icons │ ├── Icon-192.png │ └── Icon-512.png ├── manifest.json └── index.html ├── assets └── icon │ └── icon.png ├── docs └── Screenshot_1.jpg ├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── launcher_icon.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── launcher_icon.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── launcher_icon.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── launcher_icon.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── launcher_icon.png │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── values-night │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── medium │ │ │ │ │ └── unlimited │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle └── build.gradle ├── .metadata ├── .gitignore ├── test └── widget_test.dart ├── README.md ├── pubspec.yaml ├── LICENSE ├── pubspec.lock └── lib └── main.dart /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/web/favicon.png -------------------------------------------------------------------------------- /assets/icon/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/assets/icon/icon.png -------------------------------------------------------------------------------- /docs/Screenshot_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/docs/Screenshot_1.jpg -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/web/icons/Icon-512.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/android/app/src/main/res/mipmap-hdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/android/app/src/main/res/mipmap-mdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/And96/MediumUnlimited/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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-7.0.2-all.zip -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 1d9032c7e1d867f071f2277eb1673e8f9b0274e3 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/medium/unlimited/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.medium.unlimited 2 | 3 | import android.os.Bundle 4 | import io.flutter.embedding.android.FlutterActivity 5 | import android.content.Intent.FLAG_ACTIVITY_NEW_TASK 6 | 7 | class MainActivity: FlutterActivity() { 8 | override fun onCreate(savedInstanceState: Bundle?) { 9 | 10 | if (intent.getIntExtra("org.chromium.chrome.extra.TASK_ID", -1) == this.taskId) { 11 | this.finish() 12 | intent.addFlags(FLAG_ACTIVITY_NEW_TASK); 13 | startActivity(intent); 14 | } 15 | super.onCreate(savedInstanceState) 16 | } 17 | } -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "medium_unlimited", 3 | "short_name": "medium_unlimited", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.6.10' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.0.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /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:medium_unlimited/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(HomeScreen()); 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 | */ 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Medium Unlimited 2 | 3 | An Android application written with Flutter/Dart to read medium.com without limitations. 4 | 5 | ## Features 6 | - Read medium without reading limits 7 | - Dark mode for all pages 8 | - Common topics (Sidebar) 9 | - Favourite links (Sidebar) 10 | - Open links shared by others apps 11 | 12 | ## Screenshot 13 | 14 | 15 | ## Faq 16 | 17 | **How does it work (For users)?** 18 | 19 | The app works like a browser. Just navigate. 20 | 21 | **How does it work (For developers)?** 22 | 23 | Under the hood, there is the package InAppWebView which clear cookies/data everytime the page change. 24 | 25 | **Can I login to Medium?** 26 | 27 | No. Read as a guest. 28 | 29 | **Which websites are supported?** 30 | 31 | It's built for Medium, but it works with custom domains too. (E.g. betterprogramming.pub) Potentially it can work with every website. 32 | 33 | **Does it unlock other browsers?** 34 | 35 | No. No other apps are involved. Everyting works only inside in this app. 36 | 37 | ## How to build 38 | ``` 39 | flutter packages get 40 | flutter packages pub run flutter_launcher_icons:main 41 | flutter pub run change_app_package_name:main com.medium.unlimited 42 | flutter build apk --release 43 | ``` 44 | 45 | ## Download 46 | [Latest APK here](https://github.com/And96/MediumUnlimited/releases/latest) 47 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | medium_unlimited 30 | 31 | 32 | 33 | 36 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | Medium Unlimited 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 | -------------------------------------------------------------------------------- /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 31 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | defaultConfig { 36 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 37 | applicationId "com.medium.unlimited" 38 | minSdkVersion 21 39 | targetSdkVersion 31 40 | versionCode flutterVersionCode.toInteger() 41 | versionName flutterVersionName 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 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 59 | } 60 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: medium_unlimited 2 | description: 'Read medium.com without limitation' 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.2.2+1 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | 27 | cupertino_icons: ^1.0.3 28 | flutter_inappwebview: ^5.3.2 29 | url_launcher: ^6.0.12 30 | back_button_interceptor: ^5.0.2 31 | receive_sharing_intent: ^1.4.5 32 | share: ^2.0.4 33 | shared_preferences: ^2.0.8 34 | restart_app: ^1.1.0 35 | share_plus: ^4.0.7 36 | 37 | dev_dependencies: 38 | flutter_test: 39 | sdk: flutter 40 | 41 | flutter_launcher_icons: ^0.9.2 42 | 43 | change_app_package_name: ^1.0.0 44 | 45 | flutter_icons: 46 | android: true 47 | ios: true 48 | image_path: "assets/icon/icon.png" 49 | image_path_ios: "assets/icon/icon.png" 50 | image_path_android: "assets/icon/icon.png" 51 | remove_alpha_ios: true 52 | 53 | # For information on the generic Dart part of this file, see the 54 | # following page: https://dart.dev/tools/pub/pubspec 55 | 56 | # The following section is specific to Flutter. 57 | flutter: 58 | 59 | # The following line ensures that the Material Icons font is 60 | # included with your application, so that you can use the icons in 61 | # the material Icons class. 62 | uses-material-design: true 63 | 64 | # To add assets to your application, add an assets section, like this: 65 | # assets: 66 | # - images/a_dot_burr.jpeg 67 | # - images/a_dot_ham.jpeg 68 | 69 | # An image asset can refer to one or more resolution-specific "variants", see 70 | # https://flutter.dev/assets-and-images/#resolution-aware. 71 | 72 | # For details regarding adding assets from package dependencies, see 73 | # https://flutter.dev/assets-and-images/#from-packages 74 | 75 | # To add custom fonts to your application, add a fonts section here, 76 | # in this "flutter" section. Each entry in this list should have a 77 | # "family" key with the font family name, and a "fonts" key with a 78 | # list giving the asset and other descriptors for the font. For 79 | # example: 80 | # fonts: 81 | # - family: Schyler 82 | # fonts: 83 | # - asset: fonts/Schyler-Regular.ttf 84 | # - asset: fonts/Schyler-Italic.ttf 85 | # style: italic 86 | # - family: Trajan Pro 87 | # fonts: 88 | # - asset: fonts/TrajanPro.ttf 89 | # - asset: fonts/TrajanPro_Bold.ttf 90 | # weight: 700 91 | # 92 | # For details regarding fonts from package dependencies, 93 | # see https://flutter.dev/custom-fonts/#from-packages 94 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 46 | 50 | 55 | 59 | 60 | 61 | 62 | 63 | 64 | 66 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | archive: 5 | dependency: transitive 6 | description: 7 | name: archive 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "3.3.0" 11 | args: 12 | dependency: transitive 13 | description: 14 | name: args 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.3.1" 18 | async: 19 | dependency: transitive 20 | description: 21 | name: async 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "2.8.2" 25 | back_button_interceptor: 26 | dependency: "direct main" 27 | description: 28 | name: back_button_interceptor 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "5.0.2" 32 | boolean_selector: 33 | dependency: transitive 34 | description: 35 | name: boolean_selector 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "2.1.0" 39 | change_app_package_name: 40 | dependency: "direct dev" 41 | description: 42 | name: change_app_package_name 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.1.0" 46 | characters: 47 | dependency: transitive 48 | description: 49 | name: characters 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.2.0" 53 | charcode: 54 | dependency: transitive 55 | description: 56 | name: charcode 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "1.3.1" 60 | clock: 61 | dependency: transitive 62 | description: 63 | name: clock 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.1.0" 67 | collection: 68 | dependency: transitive 69 | description: 70 | name: collection 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "1.16.0" 74 | crypto: 75 | dependency: transitive 76 | description: 77 | name: crypto 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "3.0.2" 81 | cupertino_icons: 82 | dependency: "direct main" 83 | description: 84 | name: cupertino_icons 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "1.0.5" 88 | fake_async: 89 | dependency: transitive 90 | description: 91 | name: fake_async 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "1.3.0" 95 | ffi: 96 | dependency: transitive 97 | description: 98 | name: ffi 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "2.0.0" 102 | file: 103 | dependency: transitive 104 | description: 105 | name: file 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "6.1.2" 109 | flutter: 110 | dependency: "direct main" 111 | description: flutter 112 | source: sdk 113 | version: "0.0.0" 114 | flutter_inappwebview: 115 | dependency: "direct main" 116 | description: 117 | name: flutter_inappwebview 118 | url: "https://pub.dartlang.org" 119 | source: hosted 120 | version: "5.4.3+7" 121 | flutter_launcher_icons: 122 | dependency: "direct dev" 123 | description: 124 | name: flutter_launcher_icons 125 | url: "https://pub.dartlang.org" 126 | source: hosted 127 | version: "0.9.3" 128 | flutter_test: 129 | dependency: "direct dev" 130 | description: flutter 131 | source: sdk 132 | version: "0.0.0" 133 | flutter_web_plugins: 134 | dependency: transitive 135 | description: flutter 136 | source: sdk 137 | version: "0.0.0" 138 | image: 139 | dependency: transitive 140 | description: 141 | name: image 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "3.2.0" 145 | js: 146 | dependency: transitive 147 | description: 148 | name: js 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "0.6.4" 152 | matcher: 153 | dependency: transitive 154 | description: 155 | name: matcher 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "0.12.11" 159 | material_color_utilities: 160 | dependency: transitive 161 | description: 162 | name: material_color_utilities 163 | url: "https://pub.dartlang.org" 164 | source: hosted 165 | version: "0.1.4" 166 | meta: 167 | dependency: transitive 168 | description: 169 | name: meta 170 | url: "https://pub.dartlang.org" 171 | source: hosted 172 | version: "1.7.0" 173 | mime: 174 | dependency: transitive 175 | description: 176 | name: mime 177 | url: "https://pub.dartlang.org" 178 | source: hosted 179 | version: "1.0.2" 180 | path: 181 | dependency: transitive 182 | description: 183 | name: path 184 | url: "https://pub.dartlang.org" 185 | source: hosted 186 | version: "1.8.1" 187 | path_provider_linux: 188 | dependency: transitive 189 | description: 190 | name: path_provider_linux 191 | url: "https://pub.dartlang.org" 192 | source: hosted 193 | version: "2.1.7" 194 | path_provider_platform_interface: 195 | dependency: transitive 196 | description: 197 | name: path_provider_platform_interface 198 | url: "https://pub.dartlang.org" 199 | source: hosted 200 | version: "2.0.4" 201 | path_provider_windows: 202 | dependency: transitive 203 | description: 204 | name: path_provider_windows 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "2.1.0" 208 | petitparser: 209 | dependency: transitive 210 | description: 211 | name: petitparser 212 | url: "https://pub.dartlang.org" 213 | source: hosted 214 | version: "5.0.0" 215 | platform: 216 | dependency: transitive 217 | description: 218 | name: platform 219 | url: "https://pub.dartlang.org" 220 | source: hosted 221 | version: "3.1.0" 222 | plugin_platform_interface: 223 | dependency: transitive 224 | description: 225 | name: plugin_platform_interface 226 | url: "https://pub.dartlang.org" 227 | source: hosted 228 | version: "2.1.2" 229 | process: 230 | dependency: transitive 231 | description: 232 | name: process 233 | url: "https://pub.dartlang.org" 234 | source: hosted 235 | version: "4.2.4" 236 | receive_sharing_intent: 237 | dependency: "direct main" 238 | description: 239 | name: receive_sharing_intent 240 | url: "https://pub.dartlang.org" 241 | source: hosted 242 | version: "1.4.5" 243 | restart_app: 244 | dependency: "direct main" 245 | description: 246 | name: restart_app 247 | url: "https://pub.dartlang.org" 248 | source: hosted 249 | version: "1.1.0+1" 250 | share: 251 | dependency: "direct main" 252 | description: 253 | name: share 254 | url: "https://pub.dartlang.org" 255 | source: hosted 256 | version: "2.0.4" 257 | share_plus: 258 | dependency: "direct main" 259 | description: 260 | name: share_plus 261 | url: "https://pub.dartlang.org" 262 | source: hosted 263 | version: "4.0.7" 264 | share_plus_linux: 265 | dependency: transitive 266 | description: 267 | name: share_plus_linux 268 | url: "https://pub.dartlang.org" 269 | source: hosted 270 | version: "3.0.0" 271 | share_plus_macos: 272 | dependency: transitive 273 | description: 274 | name: share_plus_macos 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "3.0.1" 278 | share_plus_platform_interface: 279 | dependency: transitive 280 | description: 281 | name: share_plus_platform_interface 282 | url: "https://pub.dartlang.org" 283 | source: hosted 284 | version: "3.0.3" 285 | share_plus_web: 286 | dependency: transitive 287 | description: 288 | name: share_plus_web 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "3.0.1" 292 | share_plus_windows: 293 | dependency: transitive 294 | description: 295 | name: share_plus_windows 296 | url: "https://pub.dartlang.org" 297 | source: hosted 298 | version: "3.0.1" 299 | shared_preferences: 300 | dependency: "direct main" 301 | description: 302 | name: shared_preferences 303 | url: "https://pub.dartlang.org" 304 | source: hosted 305 | version: "2.0.15" 306 | shared_preferences_android: 307 | dependency: transitive 308 | description: 309 | name: shared_preferences_android 310 | url: "https://pub.dartlang.org" 311 | source: hosted 312 | version: "2.0.12" 313 | shared_preferences_ios: 314 | dependency: transitive 315 | description: 316 | name: shared_preferences_ios 317 | url: "https://pub.dartlang.org" 318 | source: hosted 319 | version: "2.1.1" 320 | shared_preferences_linux: 321 | dependency: transitive 322 | description: 323 | name: shared_preferences_linux 324 | url: "https://pub.dartlang.org" 325 | source: hosted 326 | version: "2.1.1" 327 | shared_preferences_macos: 328 | dependency: transitive 329 | description: 330 | name: shared_preferences_macos 331 | url: "https://pub.dartlang.org" 332 | source: hosted 333 | version: "2.0.4" 334 | shared_preferences_platform_interface: 335 | dependency: transitive 336 | description: 337 | name: shared_preferences_platform_interface 338 | url: "https://pub.dartlang.org" 339 | source: hosted 340 | version: "2.0.0" 341 | shared_preferences_web: 342 | dependency: transitive 343 | description: 344 | name: shared_preferences_web 345 | url: "https://pub.dartlang.org" 346 | source: hosted 347 | version: "2.0.4" 348 | shared_preferences_windows: 349 | dependency: transitive 350 | description: 351 | name: shared_preferences_windows 352 | url: "https://pub.dartlang.org" 353 | source: hosted 354 | version: "2.1.1" 355 | sky_engine: 356 | dependency: transitive 357 | description: flutter 358 | source: sdk 359 | version: "0.0.99" 360 | source_span: 361 | dependency: transitive 362 | description: 363 | name: source_span 364 | url: "https://pub.dartlang.org" 365 | source: hosted 366 | version: "1.8.2" 367 | stack_trace: 368 | dependency: transitive 369 | description: 370 | name: stack_trace 371 | url: "https://pub.dartlang.org" 372 | source: hosted 373 | version: "1.10.0" 374 | stream_channel: 375 | dependency: transitive 376 | description: 377 | name: stream_channel 378 | url: "https://pub.dartlang.org" 379 | source: hosted 380 | version: "2.1.0" 381 | string_scanner: 382 | dependency: transitive 383 | description: 384 | name: string_scanner 385 | url: "https://pub.dartlang.org" 386 | source: hosted 387 | version: "1.1.0" 388 | term_glyph: 389 | dependency: transitive 390 | description: 391 | name: term_glyph 392 | url: "https://pub.dartlang.org" 393 | source: hosted 394 | version: "1.2.0" 395 | test_api: 396 | dependency: transitive 397 | description: 398 | name: test_api 399 | url: "https://pub.dartlang.org" 400 | source: hosted 401 | version: "0.4.9" 402 | typed_data: 403 | dependency: transitive 404 | description: 405 | name: typed_data 406 | url: "https://pub.dartlang.org" 407 | source: hosted 408 | version: "1.3.1" 409 | url_launcher: 410 | dependency: "direct main" 411 | description: 412 | name: url_launcher 413 | url: "https://pub.dartlang.org" 414 | source: hosted 415 | version: "6.1.3" 416 | url_launcher_android: 417 | dependency: transitive 418 | description: 419 | name: url_launcher_android 420 | url: "https://pub.dartlang.org" 421 | source: hosted 422 | version: "6.0.17" 423 | url_launcher_ios: 424 | dependency: transitive 425 | description: 426 | name: url_launcher_ios 427 | url: "https://pub.dartlang.org" 428 | source: hosted 429 | version: "6.0.17" 430 | url_launcher_linux: 431 | dependency: transitive 432 | description: 433 | name: url_launcher_linux 434 | url: "https://pub.dartlang.org" 435 | source: hosted 436 | version: "3.0.1" 437 | url_launcher_macos: 438 | dependency: transitive 439 | description: 440 | name: url_launcher_macos 441 | url: "https://pub.dartlang.org" 442 | source: hosted 443 | version: "3.0.1" 444 | url_launcher_platform_interface: 445 | dependency: transitive 446 | description: 447 | name: url_launcher_platform_interface 448 | url: "https://pub.dartlang.org" 449 | source: hosted 450 | version: "2.0.5" 451 | url_launcher_web: 452 | dependency: transitive 453 | description: 454 | name: url_launcher_web 455 | url: "https://pub.dartlang.org" 456 | source: hosted 457 | version: "2.0.11" 458 | url_launcher_windows: 459 | dependency: transitive 460 | description: 461 | name: url_launcher_windows 462 | url: "https://pub.dartlang.org" 463 | source: hosted 464 | version: "3.0.1" 465 | vector_math: 466 | dependency: transitive 467 | description: 468 | name: vector_math 469 | url: "https://pub.dartlang.org" 470 | source: hosted 471 | version: "2.1.2" 472 | win32: 473 | dependency: transitive 474 | description: 475 | name: win32 476 | url: "https://pub.dartlang.org" 477 | source: hosted 478 | version: "2.7.0" 479 | xdg_directories: 480 | dependency: transitive 481 | description: 482 | name: xdg_directories 483 | url: "https://pub.dartlang.org" 484 | source: hosted 485 | version: "0.2.0+1" 486 | xml: 487 | dependency: transitive 488 | description: 489 | name: xml 490 | url: "https://pub.dartlang.org" 491 | source: hosted 492 | version: "6.1.0" 493 | yaml: 494 | dependency: transitive 495 | description: 496 | name: yaml 497 | url: "https://pub.dartlang.org" 498 | source: hosted 499 | version: "3.1.1" 500 | sdks: 501 | dart: ">=2.17.0 <3.0.0" 502 | flutter: ">=3.0.0" 503 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXCopyFilesBuildPhase section */ 19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 20 | isa = PBXCopyFilesBuildPhase; 21 | buildActionMask = 2147483647; 22 | dstPath = ""; 23 | dstSubfolderSpec = 10; 24 | files = ( 25 | ); 26 | name = "Embed Frameworks"; 27 | runOnlyForDeploymentPostprocessing = 0; 28 | }; 29 | /* End PBXCopyFilesBuildPhase section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 9740EEB11CF90186004384FC /* Flutter */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 65 | ); 66 | name = Flutter; 67 | sourceTree = ""; 68 | }; 69 | 97C146E51CF9000F007C117D = { 70 | isa = PBXGroup; 71 | children = ( 72 | 9740EEB11CF90186004384FC /* Flutter */, 73 | 97C146F01CF9000F007C117D /* Runner */, 74 | 97C146EF1CF9000F007C117D /* Products */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 97C146EF1CF9000F007C117D /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 97C146EE1CF9000F007C117D /* Runner.app */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | 97C146F01CF9000F007C117D /* Runner */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 92 | 97C147021CF9000F007C117D /* Info.plist */, 93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 97 | ); 98 | path = Runner; 99 | sourceTree = ""; 100 | }; 101 | /* End PBXGroup section */ 102 | 103 | /* Begin PBXNativeTarget section */ 104 | 97C146ED1CF9000F007C117D /* Runner */ = { 105 | isa = PBXNativeTarget; 106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 107 | buildPhases = ( 108 | 9740EEB61CF901F6004384FC /* Run Script */, 109 | 97C146EA1CF9000F007C117D /* Sources */, 110 | 97C146EB1CF9000F007C117D /* Frameworks */, 111 | 97C146EC1CF9000F007C117D /* Resources */, 112 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 114 | ); 115 | buildRules = ( 116 | ); 117 | dependencies = ( 118 | ); 119 | name = Runner; 120 | productName = Runner; 121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 122 | productType = "com.apple.product-type.application"; 123 | }; 124 | /* End PBXNativeTarget section */ 125 | 126 | /* Begin PBXProject section */ 127 | 97C146E61CF9000F007C117D /* Project object */ = { 128 | isa = PBXProject; 129 | attributes = { 130 | LastUpgradeCheck = 1020; 131 | ORGANIZATIONNAME = ""; 132 | TargetAttributes = { 133 | 97C146ED1CF9000F007C117D = { 134 | CreatedOnToolsVersion = 7.3.1; 135 | LastSwiftMigration = 1100; 136 | }; 137 | }; 138 | }; 139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 140 | compatibilityVersion = "Xcode 9.3"; 141 | developmentRegion = en; 142 | hasScannedForEncodings = 0; 143 | knownRegions = ( 144 | en, 145 | Base, 146 | ); 147 | mainGroup = 97C146E51CF9000F007C117D; 148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 149 | projectDirPath = ""; 150 | projectRoot = ""; 151 | targets = ( 152 | 97C146ED1CF9000F007C117D /* Runner */, 153 | ); 154 | }; 155 | /* End PBXProject section */ 156 | 157 | /* Begin PBXResourcesBuildPhase section */ 158 | 97C146EC1CF9000F007C117D /* Resources */ = { 159 | isa = PBXResourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXShellScriptBuildPhase section */ 172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 173 | isa = PBXShellScriptBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | ); 177 | inputPaths = ( 178 | ); 179 | name = "Thin Binary"; 180 | outputPaths = ( 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | shellPath = /bin/sh; 184 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 185 | }; 186 | 9740EEB61CF901F6004384FC /* Run Script */ = { 187 | isa = PBXShellScriptBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | ); 191 | inputPaths = ( 192 | ); 193 | name = "Run Script"; 194 | outputPaths = ( 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | shellPath = /bin/sh; 198 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 199 | }; 200 | /* End PBXShellScriptBuildPhase section */ 201 | 202 | /* Begin PBXSourcesBuildPhase section */ 203 | 97C146EA1CF9000F007C117D /* Sources */ = { 204 | isa = PBXSourcesBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 208 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXSourcesBuildPhase section */ 213 | 214 | /* Begin PBXVariantGroup section */ 215 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 216 | isa = PBXVariantGroup; 217 | children = ( 218 | 97C146FB1CF9000F007C117D /* Base */, 219 | ); 220 | name = Main.storyboard; 221 | sourceTree = ""; 222 | }; 223 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 224 | isa = PBXVariantGroup; 225 | children = ( 226 | 97C147001CF9000F007C117D /* Base */, 227 | ); 228 | name = LaunchScreen.storyboard; 229 | sourceTree = ""; 230 | }; 231 | /* End PBXVariantGroup section */ 232 | 233 | /* Begin XCBuildConfiguration section */ 234 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 235 | isa = XCBuildConfiguration; 236 | buildSettings = { 237 | ALWAYS_SEARCH_USER_PATHS = NO; 238 | CLANG_ANALYZER_NONNULL = YES; 239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 240 | CLANG_CXX_LIBRARY = "libc++"; 241 | CLANG_ENABLE_MODULES = YES; 242 | CLANG_ENABLE_OBJC_ARC = YES; 243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 244 | CLANG_WARN_BOOL_CONVERSION = YES; 245 | CLANG_WARN_COMMA = YES; 246 | CLANG_WARN_CONSTANT_CONVERSION = YES; 247 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 249 | CLANG_WARN_EMPTY_BODY = YES; 250 | CLANG_WARN_ENUM_CONVERSION = YES; 251 | CLANG_WARN_INFINITE_RECURSION = YES; 252 | CLANG_WARN_INT_CONVERSION = YES; 253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 258 | CLANG_WARN_STRICT_PROTOTYPES = YES; 259 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 260 | CLANG_WARN_UNREACHABLE_CODE = YES; 261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 263 | COPY_PHASE_STRIP = NO; 264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 265 | ENABLE_NS_ASSERTIONS = NO; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | GCC_C_LANGUAGE_STANDARD = gnu99; 268 | GCC_NO_COMMON_BLOCKS = YES; 269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 271 | GCC_WARN_UNDECLARED_SELECTOR = YES; 272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 273 | GCC_WARN_UNUSED_FUNCTION = YES; 274 | GCC_WARN_UNUSED_VARIABLE = YES; 275 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 276 | MTL_ENABLE_DEBUG_INFO = NO; 277 | SDKROOT = iphoneos; 278 | SUPPORTED_PLATFORMS = iphoneos; 279 | TARGETED_DEVICE_FAMILY = "1,2"; 280 | VALIDATE_PRODUCT = YES; 281 | }; 282 | name = Profile; 283 | }; 284 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 285 | isa = XCBuildConfiguration; 286 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 287 | buildSettings = { 288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 289 | CLANG_ENABLE_MODULES = YES; 290 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 291 | ENABLE_BITCODE = NO; 292 | INFOPLIST_FILE = Runner/Info.plist; 293 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 294 | PRODUCT_BUNDLE_IDENTIFIER = com.example.mediumUnlimited; 295 | PRODUCT_NAME = "$(TARGET_NAME)"; 296 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 297 | SWIFT_VERSION = 5.0; 298 | VERSIONING_SYSTEM = "apple-generic"; 299 | }; 300 | name = Profile; 301 | }; 302 | 97C147031CF9000F007C117D /* Debug */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ALWAYS_SEARCH_USER_PATHS = NO; 306 | CLANG_ANALYZER_NONNULL = YES; 307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 308 | CLANG_CXX_LIBRARY = "libc++"; 309 | CLANG_ENABLE_MODULES = YES; 310 | CLANG_ENABLE_OBJC_ARC = YES; 311 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_COMMA = YES; 314 | CLANG_WARN_CONSTANT_CONVERSION = YES; 315 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 316 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 317 | CLANG_WARN_EMPTY_BODY = YES; 318 | CLANG_WARN_ENUM_CONVERSION = YES; 319 | CLANG_WARN_INFINITE_RECURSION = YES; 320 | CLANG_WARN_INT_CONVERSION = YES; 321 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 322 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 323 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 325 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 326 | CLANG_WARN_STRICT_PROTOTYPES = YES; 327 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 328 | CLANG_WARN_UNREACHABLE_CODE = YES; 329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 330 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 331 | COPY_PHASE_STRIP = NO; 332 | DEBUG_INFORMATION_FORMAT = dwarf; 333 | ENABLE_STRICT_OBJC_MSGSEND = YES; 334 | ENABLE_TESTABILITY = YES; 335 | GCC_C_LANGUAGE_STANDARD = gnu99; 336 | GCC_DYNAMIC_NO_PIC = NO; 337 | GCC_NO_COMMON_BLOCKS = YES; 338 | GCC_OPTIMIZATION_LEVEL = 0; 339 | GCC_PREPROCESSOR_DEFINITIONS = ( 340 | "DEBUG=1", 341 | "$(inherited)", 342 | ); 343 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 344 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 345 | GCC_WARN_UNDECLARED_SELECTOR = YES; 346 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 347 | GCC_WARN_UNUSED_FUNCTION = YES; 348 | GCC_WARN_UNUSED_VARIABLE = YES; 349 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 350 | MTL_ENABLE_DEBUG_INFO = YES; 351 | ONLY_ACTIVE_ARCH = YES; 352 | SDKROOT = iphoneos; 353 | TARGETED_DEVICE_FAMILY = "1,2"; 354 | }; 355 | name = Debug; 356 | }; 357 | 97C147041CF9000F007C117D /* Release */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | ALWAYS_SEARCH_USER_PATHS = NO; 361 | CLANG_ANALYZER_NONNULL = YES; 362 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 363 | CLANG_CXX_LIBRARY = "libc++"; 364 | CLANG_ENABLE_MODULES = YES; 365 | CLANG_ENABLE_OBJC_ARC = YES; 366 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 367 | CLANG_WARN_BOOL_CONVERSION = YES; 368 | CLANG_WARN_COMMA = YES; 369 | CLANG_WARN_CONSTANT_CONVERSION = YES; 370 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 371 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 372 | CLANG_WARN_EMPTY_BODY = YES; 373 | CLANG_WARN_ENUM_CONVERSION = YES; 374 | CLANG_WARN_INFINITE_RECURSION = YES; 375 | CLANG_WARN_INT_CONVERSION = YES; 376 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 377 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 378 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 379 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 380 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 381 | CLANG_WARN_STRICT_PROTOTYPES = YES; 382 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 383 | CLANG_WARN_UNREACHABLE_CODE = YES; 384 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 385 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 386 | COPY_PHASE_STRIP = NO; 387 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 388 | ENABLE_NS_ASSERTIONS = NO; 389 | ENABLE_STRICT_OBJC_MSGSEND = YES; 390 | GCC_C_LANGUAGE_STANDARD = gnu99; 391 | GCC_NO_COMMON_BLOCKS = YES; 392 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 393 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 394 | GCC_WARN_UNDECLARED_SELECTOR = YES; 395 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 396 | GCC_WARN_UNUSED_FUNCTION = YES; 397 | GCC_WARN_UNUSED_VARIABLE = YES; 398 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 399 | MTL_ENABLE_DEBUG_INFO = NO; 400 | SDKROOT = iphoneos; 401 | SUPPORTED_PLATFORMS = iphoneos; 402 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 403 | TARGETED_DEVICE_FAMILY = "1,2"; 404 | VALIDATE_PRODUCT = YES; 405 | }; 406 | name = Release; 407 | }; 408 | 97C147061CF9000F007C117D /* Debug */ = { 409 | isa = XCBuildConfiguration; 410 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 411 | buildSettings = { 412 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 413 | CLANG_ENABLE_MODULES = YES; 414 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 415 | ENABLE_BITCODE = NO; 416 | INFOPLIST_FILE = Runner/Info.plist; 417 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 418 | PRODUCT_BUNDLE_IDENTIFIER = com.example.mediumUnlimited; 419 | PRODUCT_NAME = "$(TARGET_NAME)"; 420 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 421 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 422 | SWIFT_VERSION = 5.0; 423 | VERSIONING_SYSTEM = "apple-generic"; 424 | }; 425 | name = Debug; 426 | }; 427 | 97C147071CF9000F007C117D /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 430 | buildSettings = { 431 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 432 | CLANG_ENABLE_MODULES = YES; 433 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 434 | ENABLE_BITCODE = NO; 435 | INFOPLIST_FILE = Runner/Info.plist; 436 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 437 | PRODUCT_BUNDLE_IDENTIFIER = com.example.mediumUnlimited; 438 | PRODUCT_NAME = "$(TARGET_NAME)"; 439 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 440 | SWIFT_VERSION = 5.0; 441 | VERSIONING_SYSTEM = "apple-generic"; 442 | }; 443 | name = Release; 444 | }; 445 | /* End XCBuildConfiguration section */ 446 | 447 | /* Begin XCConfigurationList section */ 448 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 449 | isa = XCConfigurationList; 450 | buildConfigurations = ( 451 | 97C147031CF9000F007C117D /* Debug */, 452 | 97C147041CF9000F007C117D /* Release */, 453 | 249021D3217E4FDB00AE95B9 /* Profile */, 454 | ); 455 | defaultConfigurationIsVisible = 0; 456 | defaultConfigurationName = Release; 457 | }; 458 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 459 | isa = XCConfigurationList; 460 | buildConfigurations = ( 461 | 97C147061CF9000F007C117D /* Debug */, 462 | 97C147071CF9000F007C117D /* Release */, 463 | 249021D4217E4FDB00AE95B9 /* Profile */, 464 | ); 465 | defaultConfigurationIsVisible = 0; 466 | defaultConfigurationName = Release; 467 | }; 468 | /* End XCConfigurationList section */ 469 | }; 470 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 471 | } -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: cancel_subscriptions 2 | 3 | import 'dart:async'; 4 | //import 'dart:io'; 5 | import 'package:flutter/services.dart'; 6 | //import 'package:restart_app/restart_app.dart'; 7 | //import 'dart:io'; 8 | import 'package:receive_sharing_intent/receive_sharing_intent.dart'; 9 | import 'package:flutter/material.dart'; 10 | import 'package:flutter_inappwebview/flutter_inappwebview.dart'; 11 | import 'package:url_launcher/url_launcher.dart'; 12 | import 'package:back_button_interceptor/back_button_interceptor.dart'; 13 | import 'package:share_plus/share_plus.dart'; 14 | import 'package:shared_preferences/shared_preferences.dart'; 15 | 16 | Future main() async { 17 | WidgetsFlutterBinding.ensureInitialized(); 18 | /*if (Platform.isAndroid) { 19 | await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true); 20 | }*/ 21 | runApp(MaterialApp( 22 | debugShowCheckedModeBanner: false, 23 | theme: ThemeData( 24 | colorScheme: ColorScheme.fromSwatch( 25 | primarySwatch: Colors.grey, 26 | primaryColorDark: Colors.grey[700], 27 | accentColor: Colors.grey[700], 28 | brightness: Brightness.dark, 29 | backgroundColor: Colors.grey[900]) 30 | .copyWith( 31 | secondary: Colors.green, 32 | ), 33 | textTheme: const TextTheme(bodyText2: TextStyle(color: Colors.purple)), 34 | ), 35 | home: HomeScreen(), 36 | )); 37 | } 38 | 39 | class HomeScreen extends StatefulWidget { 40 | @override 41 | _HomeScreenState createState() => new _HomeScreenState(); 42 | } 43 | 44 | class DropdownChoices { 45 | const DropdownChoices({this.title = '', this.icon = Icons.access_alarm}); 46 | 47 | final String title; 48 | final IconData icon; 49 | } 50 | 51 | bool hybridComposition = true; 52 | 53 | InAppWebViewGroupOptions getInAppWebViewGroupOptions() { 54 | return InAppWebViewGroupOptions( 55 | crossPlatform: InAppWebViewOptions( 56 | javaScriptCanOpenWindowsAutomatically: false, 57 | useShouldOverrideUrlLoading: true, 58 | mediaPlaybackRequiresUserGesture: true, 59 | cacheEnabled: false, 60 | incognito: true, 61 | clearCache: true, 62 | ), 63 | android: AndroidInAppWebViewOptions( 64 | useHybridComposition: 65 | hybridComposition, //CRASH WHEN APP OPENED FROM INTENT IF USED WITH useHybridComposition 66 | clearSessionCache: true, 67 | forceDark: AndroidForceDark.FORCE_DARK_ON), 68 | ios: IOSInAppWebViewOptions( 69 | allowsInlineMediaPlayback: true, 70 | )); 71 | } 72 | 73 | class _HomeScreenState extends State with WidgetsBindingObserver { 74 | final GlobalKey webViewKey = GlobalKey(); 75 | 76 | String urlDefault = "https://medium.com/tag/popular"; 77 | String url = ""; 78 | String urlLast = ""; 79 | 80 | GlobalKey _scaffoldKey = new GlobalKey(); 81 | 82 | List dropdownChoices = [ 83 | DropdownChoices(title: 'Back', icon: Icons.arrow_back), 84 | DropdownChoices(title: 'Forward', icon: Icons.arrow_forward), 85 | DropdownChoices(title: 'Share', icon: Icons.share), 86 | DropdownChoices(title: 'Source Code', icon: Icons.code), 87 | ]; 88 | 89 | InAppWebViewController? webViewController; 90 | InAppWebViewGroupOptions options = getInAppWebViewGroupOptions(); 91 | 92 | double progress = 0; 93 | final urlController = TextEditingController(); 94 | 95 | StreamSubscription? _intentDataStreamSubscription; 96 | 97 | bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) { 98 | webViewController?.stopLoading(); 99 | webViewController?.clearCache(); 100 | webViewController?.goBack(); 101 | return true; 102 | } 103 | 104 | List? favouriteLinks = []; 105 | 106 | loadFavouriteLinks() async { 107 | SharedPreferences prefs = await SharedPreferences.getInstance(); 108 | favouriteLinks = prefs.getStringList('favourite_links'); 109 | if (favouriteLinks == null) { 110 | setState(() { 111 | favouriteLinks = []; 112 | }); 113 | } 114 | } 115 | 116 | saveLastUrl() async { 117 | SharedPreferences prefs = await SharedPreferences.getInstance(); 118 | prefs.setString('last_url', this.url.toString()); 119 | prefs.setString('last_date', DateTime.now().toString()); 120 | } 121 | 122 | addFavouriteLinks(String value) async { 123 | if (favouriteLinks == null) { 124 | setState(() { 125 | favouriteLinks = []; 126 | }); 127 | } 128 | setState(() { 129 | if (value.length > 5) { 130 | favouriteLinks?.add(value); 131 | } 132 | }); 133 | SharedPreferences prefs = await SharedPreferences.getInstance(); 134 | prefs.setStringList('favourite_links', favouriteLinks!); 135 | } 136 | 137 | deleteFavouriteLinks(String value) async { 138 | if (favouriteLinks == null) { 139 | setState(() { 140 | favouriteLinks = []; 141 | }); 142 | } 143 | for (var i = 0; i < favouriteLinks!.length.toInt(); i++) { 144 | if (favouriteLinks!.elementAt(i) == value.toString()) { 145 | setState(() { 146 | favouriteLinks?.remove(value); 147 | }); 148 | } 149 | } 150 | SharedPreferences prefs = await SharedPreferences.getInstance(); 151 | prefs.setStringList('favourite_links', favouriteLinks!); 152 | } 153 | 154 | TextEditingController _textFieldController = TextEditingController(); 155 | Future _displayTextInputDialog( 156 | BuildContext context, String text) async { 157 | webViewController 158 | ?.getUrl() 159 | .then((value) => _textFieldController.text = value.toString()); 160 | return showDialog( 161 | context: context, 162 | builder: (context) { 163 | return AlertDialog( 164 | title: Text('Enter link'), 165 | content: TextField( 166 | onChanged: (value) { 167 | setState(() {}); 168 | }, 169 | controller: _textFieldController, 170 | decoration: InputDecoration(hintText: "Url"), 171 | ), 172 | actions: [ 173 | TextButton( 174 | child: Text('Cancel'), 175 | onPressed: () { 176 | setState(() { 177 | _textFieldController.text = ''; 178 | }); 179 | Navigator.pop(context); 180 | }, 181 | ), 182 | TextButton( 183 | child: Text('Add'), 184 | onPressed: () { 185 | Navigator.pop(context); 186 | }, 187 | ), 188 | ], 189 | ); 190 | }); 191 | } 192 | 193 | showAlertDialogDeleteLink(BuildContext context, String item) { 194 | Widget cancelButton = TextButton( 195 | child: Text("No"), 196 | onPressed: () { 197 | Navigator.pop(context); 198 | }, 199 | ); 200 | Widget continueButton = TextButton( 201 | child: Text("Yes"), 202 | onPressed: () { 203 | deleteFavouriteLinks(item); 204 | Navigator.pop(context); 205 | }, 206 | ); 207 | AlertDialog alert = AlertDialog( 208 | title: Text("Confirm delete"), 209 | content: Text("Delete the selected link?"), 210 | actions: [ 211 | cancelButton, 212 | continueButton, 213 | ], 214 | ); 215 | showDialog( 216 | context: context, 217 | builder: (BuildContext context) { 218 | return alert; 219 | }, 220 | ); 221 | } 222 | 223 | @override 224 | void dispose() { 225 | print("Dispose"); 226 | super.dispose(); 227 | _intentDataStreamSubscription!.cancel(); 228 | WidgetsBinding.instance.removeObserver(this); 229 | } 230 | 231 | @override 232 | void initState() { 233 | try { 234 | super.initState(); 235 | 236 | WidgetsBinding.instance.addObserver(this); 237 | print("InitState"); 238 | 239 | loadFavouriteLinks(); 240 | 241 | SharedPreferences.getInstance().then((prefValue) => { 242 | setState(() { 243 | String? prefLastUrl = prefValue.getString('last_url'); 244 | String? prefLastDate = prefValue.getString('last_date'); 245 | 246 | if (prefLastUrl != null) { 247 | if (prefLastDate != null) { 248 | final currentTime = DateTime.now(); 249 | final diffInMinutes = currentTime 250 | .difference(DateTime.parse(prefLastDate)) 251 | .inMinutes 252 | .abs(); 253 | if (diffInMinutes < 10) { 254 | setState(() { 255 | urlLast = prefLastUrl; 256 | }); 257 | } 258 | } 259 | } 260 | 261 | if (urlLast == "") 262 | url = urlDefault; 263 | else 264 | url = urlLast; 265 | }) 266 | }); 267 | 268 | BackButtonInterceptor.add(myInterceptor); 269 | 270 | // For sharing or opening urls/text coming from outside the app while the app is in the memory 271 | _intentDataStreamSubscription = 272 | ReceiveSharingIntent.getTextStream().listen((String value) { 273 | //Restart.restartApp(); 274 | hybridComposition = false; 275 | if (value.toString().length > 5) { 276 | this.url = value; 277 | webViewController!.setOptions(options: getInAppWebViewGroupOptions()); 278 | webViewController!.loadUrl( 279 | urlRequest: URLRequest(url: Uri.parse(value.toString()))); 280 | removeElements(webViewController); 281 | } 282 | }, onError: (err) { 283 | print("getLinkStream error: $err"); 284 | }); 285 | 286 | // For sharing or opening urls/text coming from outside the app while the app is closed 287 | ReceiveSharingIntent.getInitialText().then((String? value) { 288 | //Restart.restartApp(); 289 | hybridComposition = false; 290 | if (value.toString().length > 5) { 291 | this.url = value.toString(); 292 | webViewController!.setOptions(options: this.options); 293 | webViewController!.loadUrl( 294 | urlRequest: URLRequest(url: Uri.parse(value.toString()))); 295 | } 296 | }); 297 | } catch (e) { 298 | print(e); 299 | } 300 | } 301 | 302 | @override 303 | void didChangeAppLifecycleState(AppLifecycleState state) { 304 | switch (state) { 305 | case AppLifecycleState.resumed: //--> crash not solved 306 | /*hybridComposition = false; 307 | webViewController!.setOptions(options: getInAppWebViewGroupOptions()); 308 | print("app in resumed");*/ 309 | /* Restart.restartApp(); 310 | break;*/ 311 | case AppLifecycleState.inactive: 312 | /* hybridComposition = false; 313 | webViewController!.setOptions(options: getInAppWebViewGroupOptions()); 314 | print("app in inactive");*/ 315 | /* Restart.restartApp(); 316 | break;*/ 317 | SystemNavigator.pop(); 318 | break; 319 | case AppLifecycleState.paused: 320 | /* hybridComposition = false; 321 | webViewController!.setOptions(options: getInAppWebViewGroupOptions());*/ 322 | print("app in paused"); 323 | //String urlPaused = this.url.toString(); 324 | //Restart.restartApp(); 325 | /*if (urlPaused.length > 5) { 326 | webViewController!.setOptions(options: this.options); 327 | webViewController! 328 | .loadUrl(urlRequest: URLRequest(url: Uri.parse(urlPaused))); 329 | }*/ 330 | break; 331 | case AppLifecycleState.detached: //--> crash not solved 332 | /*hybridComposition = false; 333 | webViewController!.setOptions(options: getInAppWebViewGroupOptions()); 334 | print("app in detached");*/ 335 | /* Restart.restartApp(); 336 | break;*/ 337 | } 338 | } 339 | 340 | void removeElements(InAppWebViewController? controller) { 341 | try { 342 | List jsCode = [ 343 | //'document.querySelector(`[data-testid="close-button"]`).click();', 344 | // 'document.querySelector(`[aria-label="Chiudi"]`).click();', 345 | // 'document.querySelectorAll("div").forEach( el => {if (el.ariaLabel.toUpperCase().includes("CLOSE")){el.Click()}});', 346 | // 'document.querySelectorAll("div").forEach( el => {if (el.ariaLabel.toUpperCase().includes("CHIUDI")){el.Click()}});', 347 | // 'document.getElementById("header-lohp-header-start-writing-button").style.display = "none";', 348 | // 'document.getElementById("top-nav-our-story-cta-desktop").style.display = "none";', 349 | // 'document.getElementById("top-nav-membership-cta-desktop").style.display = "none";', 350 | // 'document.getElementById("top-nav-write-cta-desktop").style.display = "none";', 351 | // 'document.getElementById("top-nav-sign-in-cta-desktop").style.display = "none";', 352 | // 'document.getElementById("top-nav-logo").style.display = "none";', 353 | // 'document.getElementById("header-background-color").style.display = "none";', 354 | // 'document.getElementById("lo-meta-header-sign-up-button").style.display = "none";', 355 | // 'document.getElementById("lo-meta-header-sign-in-link").style.display = "none";', 356 | // 'document.getElementById("header-background-color").style.display = "none";', 357 | // 'document.getElementById("top-nav-get-started-cta").style.display = "none";', 358 | // 'document.getElementById("lo-highlight-meter-1-copy").style.display = "none";', 359 | // 'document.getElementById("lo-highlight-meter-2-copy").style.display = "none";', 360 | // 'document.getElementById("lo-highlight-meter-3-copy").style.display = "none";', 361 | // 'document.getElementById("lo-highlight-meter-1-highlight-box").style.display = "none";', 362 | // 'document.getElementById("lo-highlight-meter-2-highlight-box").style.display = "none";', 363 | // 'document.getElementById("lo-highlight-meter-3-highlight-box").style.display = "none";', 364 | // 'document.getElementsByClassName("branch-journeys-top")[0].style.display = "none";', 365 | // //'document.getElementById("cv cw cx cy aj cz da s").style.display = "none";', 366 | // //'document.getElementsByClassName("mn u gs mo aj mp mq mr ms mt mu mv mw mx my mz na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt")[0].style.display = "none";', 367 | // 'document.getElementById("animated-container").style.display = "none";', 368 | // //'document.getElementsByClassName("ac ae af ag ah ai aj ak al")[0].style.display = "none";', 369 | // 'document.getElementById("credentials-picker-container").style.display = "none";', 370 | // //'document.getElementsByClassName("ah ai ix iy af iz ja jb jc jd je jf jg jh ji jj jk jl jm jn jo jp jq jr js jt ju jv jw jx jy jz ka kb kc kd")[0].style.display = "none";', 371 | // 'document.getElementById("lo-highlight-meter-1-link").style.display = "none";', 372 | // 'document.getElementById("lo-highlight-meter-2-link").style.display = "none";', 373 | // 'document.getElementById("lo-highlight-meter-3-link").style.display = "none";', 374 | // 'document.getElementsByClassName("tv")[0].click();', 375 | // //'document.getElementsByClassName("bv bw bx by bz ca cb cc bb cd tw tx cg to tp")[0].click();', 376 | // //'document.getElementsByClassName("s hw u w")[0].click();', 377 | // 'document.getElementsById("close").click();', 378 | // //'document.getElementById("kx u kz sy sz ta tb tc td te tf tg th ti dj cw tj tk tl").style.display = "none";', 379 | // //'document.getElementsByClassName("haAclf WsjYwc-haAclf")[0].style.display = "none";', 380 | // //'document.getElementsByClassName("us s ut uu")[0].style.display = "none";', 381 | // //'document.getElementsByClassName("s c")[0].style.display = "none";', 382 | // //'document.getElementsByClassName("s ap x")[0].style.display = "none";', 383 | // //'document.getElementsByClassName("n cp ng nh")[0].style.display = "none";', 384 | // //'document.getElementsByClassName("bf b gk bh nf")[0].style.display = "none";', 385 | // //'document.getElementsByClassName("ea eb ce cf cg ch ci cj ck bq cl ni nj lf)[0].style.display = "none";', 386 | // //'document.getElementsByClassName("bf b bg bh dx")[0].style.display = "none";', 387 | // 'document.getElementById("lo-ShowPostUnderCollection-navbar-open-in-app-button").style.display = "none";', 388 | // //'document.getElementsByClassName("bi bl ce cf cg ch ci cj ck bq bn bo cl lh li")[0].style.display = "none";', 389 | // //'document.getElementsByClassName("wv ww wx wy wz xa n cp")[0].style.display = "none";', 390 | // //'document.getElementsByClassName("aq xc xd xe cr")[0].style.display = "none";', 391 | // //'document.getElementsByClassName("aq xg mb cr nh")[0].style.display = "none";', 392 | // //'document.getElementsByClassName("xn xo xp xq sd xr zf")[0].style.display = "none";', 393 | // //'document.getElementsByClassName("yz n o p")[0].style.display = "none";', 394 | // 'document.getElementsByClassName("newsletter email_icon orange default")[0].style.display = "none";', 395 | // 'document.getElementById("sliderbox").style.display = "none";', 396 | // 'document.body.innerHTML = document.body.innerHTML.replace(/To make Medium work, we log user data. By using Medium, you agree to our/g, "");', 397 | // 'document.body.innerHTML = document.body.innerHTML.replace(/Privacy Policy/g, "");', 398 | // 'document.body.innerHTML = document.body.innerHTML.replace(/, including cookie policy./g, "");', 399 | // 'document.body.innerHTML = document.body.innerHTML.replace(/To make Medium work, we log user data./g, "");', 400 | // //'document.getElementsByClassName("ay az ba bb bc bd be bf bg bh jw jx bk jl jm").item(0).click();', 401 | // //'document.querySelector("ex ez hy lg lh li lj lk ll lm ln lo lp lq ga fp lr ls lt").style.cssText = `display: none;`', 402 | // 'document.getElementsByClassName("tp-backdrop tp-active")[0].style.display = "none";', //corriere 403 | // 'document.getElementsByClassName("tp-modal wall-modal fullWide")[0].style.display = "none";', //corriere 404 | // 'document.cookie.split(";").forEach(function(c) { document.cookie = c.replace(/^ +/, "").replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/"); });', 405 | // 'window.localStorage.clear();', 406 | // 'sessionStorage.clear();' 407 | 'if ((!window.location.href.includes("12ft")) && (!window.location.href.includes("@"))) { window.location.replace("https://12ft.io/" + window.location.href)}; ' 408 | 'if (window.location.href.includes("12ft") && window.location.href.includes("@")) { window.location.replace(window.location.href.replace("https://12ft.io/proxy?ref=&q=", "").replace("https://12ft.io/proxy?q=", "").replace("https://12ft.io/", "").replace("12ft.io/", ""))}; ' 409 | ]; 410 | jsCode.forEach((String js) { 411 | controller?.evaluateJavascript(source: js); 412 | }); 413 | } catch (e) {} 414 | } 415 | 416 | void choiceAction(DropdownChoices choice) { 417 | if (choice.title == "Back") { 418 | webViewController?.stopLoading(); 419 | webViewController?.clearCache(); 420 | webViewController?.goBack(); 421 | } 422 | 423 | if (choice.title == "Forward") { 424 | webViewController?.stopLoading(); 425 | webViewController?.clearCache(); 426 | webViewController?.goForward(); 427 | } 428 | 429 | if (choice.title == "Share") { 430 | webViewController?.stopLoading(); 431 | webViewController?.clearCache(); 432 | webViewController 433 | ?.getUrl() 434 | .then((value) => Share.share(value.toString())); 435 | } 436 | 437 | if (choice.title == "Source Code") { 438 | //webViewController 439 | //?.getHtml() 440 | webViewController! 441 | .evaluateJavascript( 442 | source: 443 | "window.document.getElementsByTagName('html')[0].outerHTML;") 444 | .then((value) => Share.share(value.toString())); 445 | } 446 | } 447 | 448 | @override 449 | Widget build(BuildContext context) { 450 | return Scaffold( 451 | key: _scaffoldKey, 452 | appBar: AppBar( 453 | title: Padding( 454 | padding: EdgeInsets.only(right: 0.0), 455 | child: Text("Medium Unlimited")), 456 | actions: [ 457 | IconButton( 458 | icon: Icon(Icons.refresh), 459 | onPressed: () { 460 | webViewController?.stopLoading(); 461 | webViewController?.clearCache(); 462 | webViewController?.reload(); 463 | }, 464 | ), 465 | PopupMenuButton( 466 | color: Colors.grey[900], 467 | onSelected: choiceAction, 468 | elevation: 6, 469 | itemBuilder: (BuildContext context) { 470 | return dropdownChoices.map((DropdownChoices choice) { 471 | return PopupMenuItem( 472 | value: choice, 473 | child: Row( 474 | children: [ 475 | Padding( 476 | padding: EdgeInsets.only(right: 15.0), 477 | child: Icon(choice.icon), 478 | ), 479 | Text(choice.title), 480 | ], 481 | ), 482 | ); 483 | }).toList(); 484 | }, 485 | ), 486 | ]), 487 | drawer: Drawer( 488 | child: DefaultTabController( 489 | length: 2, 490 | child: Column( 491 | mainAxisSize: MainAxisSize.max, 492 | children: [ 493 | Container( 494 | margin: EdgeInsets.all(0), 495 | color: Colors.black12, 496 | height: 110, 497 | child: DrawerHeader( 498 | child: ListTile( 499 | leading: Icon(Icons.rss_feed), 500 | contentPadding: EdgeInsets.only(left: 0.0, right: 0.0), 501 | title: Text('Medium.com'), 502 | onTap: () { 503 | FocusScope.of(context).unfocus(); 504 | webViewController?.stopLoading(); 505 | webViewController?.clearCache(); 506 | webViewController?.loadUrl( 507 | urlRequest: 508 | URLRequest(url: Uri.parse("https://medium.com"))); 509 | Navigator.pop(context); 510 | }, 511 | ), 512 | ), 513 | ), 514 | Container( 515 | height: 52, 516 | color: Colors.black12, 517 | child: TabBar( 518 | indicatorSize: TabBarIndicatorSize.tab, 519 | indicatorColor: Colors.black12, 520 | indicatorWeight: 1, 521 | tabs: [ 522 | Tab( 523 | child: Row( 524 | crossAxisAlignment: CrossAxisAlignment.center, 525 | mainAxisAlignment: MainAxisAlignment.center, 526 | children: [ 527 | Icon( 528 | Icons.label, 529 | ), 530 | SizedBox( 531 | width: 10.0, 532 | ), 533 | Text( 534 | "Topics", 535 | style: TextStyle(color: Colors.white), 536 | ), 537 | ], 538 | ), 539 | ), 540 | Tab( 541 | child: Row( 542 | crossAxisAlignment: CrossAxisAlignment.center, 543 | mainAxisAlignment: MainAxisAlignment.center, 544 | children: [ 545 | Icon( 546 | Icons.star, 547 | ), 548 | SizedBox( 549 | width: 10.0, 550 | ), 551 | Text( 552 | "Links", 553 | style: TextStyle(color: Colors.white), 554 | ), 555 | ], 556 | ), 557 | ), 558 | ]), 559 | ), 560 | Expanded( 561 | child: Container( 562 | child: TabBarView(children: [ 563 | Container( 564 | child: Container( 565 | color: Colors.grey[900], 566 | width: double.infinity, 567 | height: double.infinity, 568 | child: ListView( 569 | padding: EdgeInsets.zero, 570 | children: [ 571 | ListTile( 572 | leading: Icon(Icons.trending_up), 573 | trailing: Icon(Icons.keyboard_arrow_right), 574 | title: Text('Popular'), 575 | onTap: () { 576 | FocusScope.of(context).unfocus(); 577 | webViewController?.stopLoading(); 578 | webViewController?.clearCache(); 579 | webViewController?.loadUrl( 580 | urlRequest: URLRequest( 581 | url: Uri.parse( 582 | "https://medium.com/tag/popular"))); 583 | Navigator.pop(context); 584 | FocusManager.instance.primaryFocus!.unfocus(); 585 | }, 586 | ), 587 | ListTile( 588 | leading: Icon(Icons.person), 589 | trailing: Icon(Icons.keyboard_arrow_right), 590 | title: Text('Self'), 591 | onTap: () { 592 | FocusScope.of(context).unfocus(); 593 | webViewController?.stopLoading(); 594 | webViewController?.clearCache(); 595 | webViewController?.loadUrl( 596 | urlRequest: URLRequest( 597 | url: Uri.parse( 598 | "https://medium.com/tag/self"))); 599 | Navigator.pop(context); 600 | FocusManager.instance.primaryFocus!.unfocus(); 601 | }, 602 | ), 603 | ListTile( 604 | leading: Icon(Icons.favorite_outline), 605 | trailing: Icon(Icons.keyboard_arrow_right), 606 | title: Text('Relationships'), 607 | onTap: () { 608 | FocusScope.of(context).unfocus(); 609 | webViewController?.stopLoading(); 610 | webViewController?.clearCache(); 611 | webViewController?.loadUrl( 612 | urlRequest: URLRequest( 613 | url: Uri.parse( 614 | "https://medium.com/tag/relationships"))); 615 | Navigator.pop(context); 616 | FocusManager.instance.primaryFocus!.unfocus(); 617 | }, 618 | ), 619 | ListTile( 620 | leading: Icon(Icons.work), 621 | trailing: Icon(Icons.keyboard_arrow_right), 622 | title: Text('Productivity'), 623 | onTap: () { 624 | FocusScope.of(context).unfocus(); 625 | webViewController?.stopLoading(); 626 | webViewController?.clearCache(); 627 | webViewController?.loadUrl( 628 | urlRequest: URLRequest( 629 | url: Uri.parse( 630 | "https://medium.com/tag/productivity"))); 631 | Navigator.pop(context); 632 | FocusManager.instance.primaryFocus!.unfocus(); 633 | }, 634 | ), 635 | ListTile( 636 | leading: Icon(Icons.healing), 637 | trailing: Icon(Icons.keyboard_arrow_right), 638 | title: Text('Health'), 639 | onTap: () { 640 | FocusScope.of(context).unfocus(); 641 | webViewController?.stopLoading(); 642 | webViewController?.clearCache(); 643 | webViewController?.loadUrl( 644 | urlRequest: URLRequest( 645 | url: Uri.parse( 646 | "https://medium.com/tag/health"))); 647 | Navigator.pop(context); 648 | FocusManager.instance.primaryFocus!.unfocus(); 649 | }, 650 | ), 651 | ListTile( 652 | leading: Icon(Icons.code), 653 | trailing: Icon(Icons.keyboard_arrow_right), 654 | title: Text('Programming'), 655 | onTap: () { 656 | FocusScope.of(context).unfocus(); 657 | webViewController?.stopLoading(); 658 | webViewController?.clearCache(); 659 | webViewController?.loadUrl( 660 | urlRequest: URLRequest( 661 | url: Uri.parse( 662 | "https://medium.com/tag/programming"))); 663 | Navigator.pop(context); 664 | FocusManager.instance.primaryFocus!.unfocus(); 665 | }, 666 | ), 667 | ListTile( 668 | leading: Icon(Icons.science), 669 | trailing: Icon(Icons.keyboard_arrow_right), 670 | title: Text('Science'), 671 | onTap: () { 672 | FocusScope.of(context).unfocus(); 673 | webViewController?.stopLoading(); 674 | webViewController?.clearCache(); 675 | webViewController?.loadUrl( 676 | urlRequest: URLRequest( 677 | url: Uri.parse( 678 | "https://medium.com/tag/science"))); 679 | Navigator.pop(context); 680 | FocusManager.instance.primaryFocus!.unfocus(); 681 | }, 682 | ), 683 | ListTile( 684 | leading: Icon(Icons.people), 685 | trailing: Icon(Icons.keyboard_arrow_right), 686 | title: Text('Society'), 687 | onTap: () { 688 | FocusScope.of(context).unfocus(); 689 | webViewController?.stopLoading(); 690 | webViewController?.clearCache(); 691 | webViewController?.loadUrl( 692 | urlRequest: URLRequest( 693 | url: Uri.parse( 694 | "https://medium.com/tag/society"))); 695 | Navigator.pop(context); 696 | FocusManager.instance.primaryFocus!.unfocus(); 697 | }, 698 | ), 699 | ListTile( 700 | leading: Icon(Icons.computer), 701 | trailing: Icon(Icons.keyboard_arrow_right), 702 | title: Text('Technology'), 703 | onTap: () { 704 | FocusScope.of(context).unfocus(); 705 | webViewController?.stopLoading(); 706 | webViewController?.clearCache(); 707 | webViewController?.loadUrl( 708 | urlRequest: URLRequest( 709 | url: Uri.parse( 710 | "https://medium.com/tag/technology"))); 711 | Navigator.pop(context); 712 | FocusManager.instance.primaryFocus!.unfocus(); 713 | }, 714 | ), 715 | ]), 716 | ), 717 | ), 718 | Container( 719 | child: Container( 720 | color: Colors.grey[900], 721 | width: double.infinity, 722 | height: double.infinity, 723 | child: ListView( 724 | padding: EdgeInsets.zero, 725 | children: [ 726 | ListTile( 727 | leading: Icon(Icons.add_link), 728 | title: Text('Add link'), 729 | onTap: () async { 730 | await _displayTextInputDialog( 731 | context, _textFieldController.text); 732 | addFavouriteLinks(_textFieldController.text); 733 | Navigator.pop(context); 734 | }, 735 | ), 736 | Divider( 737 | height: 1, 738 | thickness: 1, 739 | color: Colors.grey[850]), 740 | for (var i = 0; 741 | i < favouriteLinks!.length.toInt(); 742 | i++) 743 | ListTile( 744 | leading: Icon(Icons.link), 745 | trailing: Icon(Icons.keyboard_arrow_right), 746 | title: Text(favouriteLinks!.elementAt(i)), 747 | onLongPress: () { 748 | showAlertDialogDeleteLink( 749 | context, favouriteLinks!.elementAt(i)); 750 | }, 751 | onTap: () { 752 | FocusScope.of(context).unfocus(); 753 | webViewController?.stopLoading(); 754 | webViewController?.clearCache(); 755 | webViewController?.loadUrl( 756 | urlRequest: URLRequest( 757 | url: Uri.parse( 758 | favouriteLinks!.elementAt(i)))); 759 | Navigator.pop(context); 760 | FocusManager.instance.primaryFocus! 761 | .unfocus(); 762 | }, 763 | ), 764 | ]), 765 | ), 766 | ), 767 | ]), 768 | ), 769 | ), 770 | ], 771 | ), 772 | ), 773 | ), 774 | body: SafeArea( 775 | child: Column(children: [ 776 | Padding( 777 | padding: EdgeInsets.only(left: 15.0), 778 | child: TextField( 779 | controller: urlController, 780 | keyboardType: TextInputType.url, 781 | /* onTap: () => urlController.selection = TextSelection( 782 | baseOffset: 0, extentOffset: urlController.value.text.length),*/ 783 | onSubmitted: (value) { 784 | if (!value.toString().toLowerCase().contains('http')) { 785 | if (value.toString().contains('.')) { 786 | value = "https://" + value; 787 | } 788 | } 789 | var url = Uri.parse(value); 790 | if (url.scheme.isEmpty) { 791 | url = Uri.parse(urlDefault); 792 | } 793 | webViewController?.loadUrl(urlRequest: URLRequest(url: url)); 794 | }, 795 | ), 796 | ), 797 | Expanded( 798 | child: Stack( 799 | children: [ 800 | InAppWebView( 801 | key: webViewKey, 802 | initialUrlRequest: URLRequest(url: Uri.parse(url)), 803 | initialOptions: this.options, 804 | onWebViewCreated: (controller) { 805 | webViewController = controller; 806 | var address = Uri.parse(url); 807 | if (address.scheme.isEmpty == false) { 808 | webViewController?.loadUrl( 809 | urlRequest: URLRequest(url: address)); 810 | } 811 | removeElements(controller); 812 | }, 813 | onLoadStop: (controller, url) async { 814 | setState(() { 815 | removeElements(controller); 816 | }); 817 | }, 818 | onLoadStart: (controller, url) { 819 | saveLastUrl(); 820 | removeElements(controller); 821 | controller.clearCache(); 822 | final cookieManager = CookieManager(); 823 | cookieManager.deleteAllCookies(); 824 | setState(() { 825 | this.url = url.toString(); 826 | urlController.text = this.url; 827 | }); 828 | }, 829 | androidOnPermissionRequest: 830 | (controller, origin, resources) async { 831 | return PermissionRequestResponse( 832 | resources: resources, 833 | action: PermissionRequestResponseAction.GRANT); 834 | }, 835 | shouldOverrideUrlLoading: (controller, navigationAction) async { 836 | var uri = navigationAction.request.url!; 837 | if (![ 838 | "http", 839 | "https", 840 | "file", 841 | "chrome", 842 | "data", 843 | "javascript", 844 | "about" 845 | ].contains(uri.scheme)) { 846 | if (await canLaunch(url)) { 847 | await launch( 848 | url, 849 | ); 850 | return NavigationActionPolicy.CANCEL; 851 | } 852 | } 853 | return NavigationActionPolicy.ALLOW; 854 | }, 855 | /*onLoadError: (controller, url, code, message) { 856 | },*/ 857 | onProgressChanged: (controller, progress) { 858 | /* if (progress >= 95 && progress <= 97) { 859 | if (webViewController != null) { 860 | removeElements(webViewController); 861 | } 862 | }*/ 863 | /* if (progress == 100) { 864 | if (webViewController != null) { 865 | removeElements(controller); 866 | controller.clearCache(); 867 | } 868 | }*/ 869 | if (progress >= 80 && progress <= 95) { 870 | if (webViewController != null) { 871 | removeElements(controller); 872 | controller.clearCache(); 873 | } 874 | } 875 | setState(() { 876 | this.progress = progress / 100; 877 | urlController.text = this.url; 878 | }); 879 | }, 880 | onUpdateVisitedHistory: (controller, url, androidIsReload) { 881 | setState(() { 882 | this.url = url.toString(); 883 | urlController.text = this.url; 884 | }); 885 | saveLastUrl(); 886 | }, 887 | /*onConsoleMessage: (controller, consoleMessage) { 888 | print(consoleMessage); 889 | },*/ 890 | ), 891 | progress < 2.0 892 | ? LinearProgressIndicator(value: progress) 893 | : Container(), 894 | ], 895 | ), 896 | ), 897 | ])), 898 | ); 899 | } 900 | } 901 | --------------------------------------------------------------------------------