Compare commits
5 Commits
android-ad
...
main
Author | SHA1 | Date | |
---|---|---|---|
283ad8f3f0 | |||
bc08b14dc0 | |||
a3b2760de0 | |||
4fa8e5b6fe | |||
10f95941d4 |
30
.metadata
@ -4,7 +4,7 @@
|
|||||||
# This file should be version controlled and should not be manually edited.
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
version:
|
version:
|
||||||
revision: "be698c48a6750c8cb8e61c740ca9991bb947aba2"
|
revision: "761747bfc538b5af34aa0d3fac380f1bc331ec49"
|
||||||
channel: "stable"
|
channel: "stable"
|
||||||
|
|
||||||
project_type: app
|
project_type: app
|
||||||
@ -13,26 +13,26 @@ project_type: app
|
|||||||
migration:
|
migration:
|
||||||
platforms:
|
platforms:
|
||||||
- platform: root
|
- platform: root
|
||||||
create_revision: be698c48a6750c8cb8e61c740ca9991bb947aba2
|
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
base_revision: be698c48a6750c8cb8e61c740ca9991bb947aba2
|
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
- platform: android
|
- platform: android
|
||||||
create_revision: be698c48a6750c8cb8e61c740ca9991bb947aba2
|
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
base_revision: be698c48a6750c8cb8e61c740ca9991bb947aba2
|
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
- platform: ios
|
- platform: ios
|
||||||
create_revision: be698c48a6750c8cb8e61c740ca9991bb947aba2
|
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
base_revision: be698c48a6750c8cb8e61c740ca9991bb947aba2
|
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
- platform: linux
|
- platform: linux
|
||||||
create_revision: be698c48a6750c8cb8e61c740ca9991bb947aba2
|
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
base_revision: be698c48a6750c8cb8e61c740ca9991bb947aba2
|
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
- platform: macos
|
- platform: macos
|
||||||
create_revision: be698c48a6750c8cb8e61c740ca9991bb947aba2
|
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
base_revision: be698c48a6750c8cb8e61c740ca9991bb947aba2
|
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
- platform: web
|
- platform: web
|
||||||
create_revision: be698c48a6750c8cb8e61c740ca9991bb947aba2
|
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
base_revision: be698c48a6750c8cb8e61c740ca9991bb947aba2
|
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
- platform: windows
|
- platform: windows
|
||||||
create_revision: be698c48a6750c8cb8e61c740ca9991bb947aba2
|
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
base_revision: be698c48a6750c8cb8e61c740ca9991bb947aba2
|
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
|
|
||||||
# User provided section
|
# User provided section
|
||||||
|
|
||||||
|
14
android/.gitignore
vendored
@ -1,14 +0,0 @@
|
|||||||
gradle-wrapper.jar
|
|
||||||
/.gradle
|
|
||||||
/captures/
|
|
||||||
/gradlew
|
|
||||||
/gradlew.bat
|
|
||||||
/local.properties
|
|
||||||
GeneratedPluginRegistrant.java
|
|
||||||
.cxx/
|
|
||||||
|
|
||||||
# Remember to never publicly share your keystore.
|
|
||||||
# See https://flutter.dev/to/reference-keystore
|
|
||||||
key.properties
|
|
||||||
**/*.keystore
|
|
||||||
**/*.jks
|
|
@ -1,44 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id("com.android.application")
|
|
||||||
id("kotlin-android")
|
|
||||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
|
||||||
id("dev.flutter.flutter-gradle-plugin")
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
|
||||||
namespace = "com.example.crab_ui"
|
|
||||||
compileSdk = flutter.compileSdkVersion
|
|
||||||
ndkVersion = flutter.ndkVersion
|
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_11
|
|
||||||
targetCompatibility = JavaVersion.VERSION_11
|
|
||||||
}
|
|
||||||
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = JavaVersion.VERSION_11.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
|
||||||
applicationId = "com.example.crab_ui"
|
|
||||||
// You can update the following values to match your application needs.
|
|
||||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
|
||||||
minSdk = flutter.minSdkVersion
|
|
||||||
targetSdk = flutter.targetSdkVersion
|
|
||||||
versionCode = flutter.versionCode
|
|
||||||
versionName = flutter.versionName
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTypes {
|
|
||||||
release {
|
|
||||||
// TODO: Add your own signing config for the release build.
|
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
|
||||||
signingConfig = signingConfigs.getByName("debug")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
flutter {
|
|
||||||
source = "../.."
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<!-- The INTERNET permission is required for development. Specifically,
|
|
||||||
the Flutter tool needs it to communicate with the running application
|
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
|
||||||
-->
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
|
||||||
</manifest>
|
|
@ -1,45 +0,0 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<application
|
|
||||||
android:label="crab_ui"
|
|
||||||
android:name="${applicationName}"
|
|
||||||
android:icon="@mipmap/ic_launcher">
|
|
||||||
<activity
|
|
||||||
android:name=".MainActivity"
|
|
||||||
android:exported="true"
|
|
||||||
android:launchMode="singleTop"
|
|
||||||
android:taskAffinity=""
|
|
||||||
android:theme="@style/LaunchTheme"
|
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
|
||||||
android:hardwareAccelerated="true"
|
|
||||||
android:windowSoftInputMode="adjustResize">
|
|
||||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
|
||||||
the Android process has started. This theme is visible to the user
|
|
||||||
while the Flutter UI initializes. After that, this theme continues
|
|
||||||
to determine the Window background behind the Flutter UI. -->
|
|
||||||
<meta-data
|
|
||||||
android:name="io.flutter.embedding.android.NormalTheme"
|
|
||||||
android:resource="@style/NormalTheme"
|
|
||||||
/>
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
<!-- Don't delete the meta-data below.
|
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
|
||||||
<meta-data
|
|
||||||
android:name="flutterEmbedding"
|
|
||||||
android:value="2" />
|
|
||||||
</application>
|
|
||||||
<!-- Required to query activities that can process text, see:
|
|
||||||
https://developer.android.com/training/package-visibility and
|
|
||||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
|
||||||
|
|
||||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
|
||||||
<queries>
|
|
||||||
<intent>
|
|
||||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
|
||||||
<data android:mimeType="text/plain"/>
|
|
||||||
</intent>
|
|
||||||
</queries>
|
|
||||||
</manifest>
|
|
@ -1,5 +0,0 @@
|
|||||||
package com.example.crab_ui
|
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
|
||||||
|
|
||||||
class MainActivity : FlutterActivity()
|
|
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Modify this file to customize your launch splash screen -->
|
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item android:drawable="?android:colorBackground" />
|
|
||||||
|
|
||||||
<!-- You can insert your own image assets here -->
|
|
||||||
<!-- <item>
|
|
||||||
<bitmap
|
|
||||||
android:gravity="center"
|
|
||||||
android:src="@mipmap/launch_image" />
|
|
||||||
</item> -->
|
|
||||||
</layer-list>
|
|
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Modify this file to customize your launch splash screen -->
|
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item android:drawable="@android:color/white" />
|
|
||||||
|
|
||||||
<!-- You can insert your own image assets here -->
|
|
||||||
<!-- <item>
|
|
||||||
<bitmap
|
|
||||||
android:gravity="center"
|
|
||||||
android:src="@mipmap/launch_image" />
|
|
||||||
</item> -->
|
|
||||||
</layer-list>
|
|
Before Width: | Height: | Size: 544 B |
Before Width: | Height: | Size: 442 B |
Before Width: | Height: | Size: 721 B |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.4 KiB |
@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
|
||||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
|
||||||
<!-- Show a splash screen on the activity. Automatically removed when
|
|
||||||
the Flutter engine draws its first frame -->
|
|
||||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
|
||||||
</style>
|
|
||||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
|
||||||
This theme determines the color of the Android Window while your
|
|
||||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
|
||||||
running.
|
|
||||||
|
|
||||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
|
||||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
|
||||||
<item name="android:windowBackground">?android:colorBackground</item>
|
|
||||||
</style>
|
|
||||||
</resources>
|
|
@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
|
||||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
|
||||||
<!-- Show a splash screen on the activity. Automatically removed when
|
|
||||||
the Flutter engine draws its first frame -->
|
|
||||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
|
||||||
</style>
|
|
||||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
|
||||||
This theme determines the color of the Android Window while your
|
|
||||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
|
||||||
running.
|
|
||||||
|
|
||||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
|
||||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
|
||||||
<item name="android:windowBackground">?android:colorBackground</item>
|
|
||||||
</style>
|
|
||||||
</resources>
|
|
@ -1,7 +0,0 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<!-- The INTERNET permission is required for development. Specifically,
|
|
||||||
the Flutter tool needs it to communicate with the running application
|
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
|
||||||
-->
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
|
||||||
</manifest>
|
|
@ -1,21 +0,0 @@
|
|||||||
allprojects {
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
|
|
||||||
rootProject.layout.buildDirectory.value(newBuildDir)
|
|
||||||
|
|
||||||
subprojects {
|
|
||||||
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
|
||||||
project.layout.buildDirectory.value(newSubprojectBuildDir)
|
|
||||||
}
|
|
||||||
subprojects {
|
|
||||||
project.evaluationDependsOn(":app")
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register<Delete>("clean") {
|
|
||||||
delete(rootProject.layout.buildDirectory)
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
|
||||||
android.useAndroidX=true
|
|
||||||
android.enableJetifier=true
|
|
@ -1,5 +0,0 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
|
||||||
distributionPath=wrapper/dists
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
|
|
@ -1,25 +0,0 @@
|
|||||||
pluginManagement {
|
|
||||||
val flutterSdkPath = run {
|
|
||||||
val properties = java.util.Properties()
|
|
||||||
file("local.properties").inputStream().use { properties.load(it) }
|
|
||||||
val flutterSdkPath = properties.getProperty("flutter.sdk")
|
|
||||||
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
|
|
||||||
flutterSdkPath
|
|
||||||
}
|
|
||||||
|
|
||||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
gradlePluginPortal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
|
||||||
id("com.android.application") version "8.7.3" apply false
|
|
||||||
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
|
|
||||||
}
|
|
||||||
|
|
||||||
include(":app")
|
|
13
android_old/.gitignore
vendored
@ -1,13 +0,0 @@
|
|||||||
gradle-wrapper.jar
|
|
||||||
/.gradle
|
|
||||||
/captures/
|
|
||||||
/gradlew
|
|
||||||
/gradlew.bat
|
|
||||||
/local.properties
|
|
||||||
GeneratedPluginRegistrant.java
|
|
||||||
|
|
||||||
# Remember to never publicly share your keystore.
|
|
||||||
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
|
|
||||||
key.properties
|
|
||||||
**/*.keystore
|
|
||||||
**/*.jks
|
|
@ -1,58 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id "com.android.application"
|
|
||||||
id "kotlin-android"
|
|
||||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
|
||||||
id "dev.flutter.flutter-gradle-plugin"
|
|
||||||
}
|
|
||||||
|
|
||||||
def localProperties = new Properties()
|
|
||||||
def localPropertiesFile = rootProject.file("local.properties")
|
|
||||||
if (localPropertiesFile.exists()) {
|
|
||||||
localPropertiesFile.withReader("UTF-8") { reader ->
|
|
||||||
localProperties.load(reader)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
|
|
||||||
if (flutterVersionCode == null) {
|
|
||||||
flutterVersionCode = "1"
|
|
||||||
}
|
|
||||||
|
|
||||||
def flutterVersionName = localProperties.getProperty("flutter.versionName")
|
|
||||||
if (flutterVersionName == null) {
|
|
||||||
flutterVersionName = "1.0"
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
|
||||||
namespace = "com.example.hym_ui"
|
|
||||||
compileSdk = flutter.compileSdkVersion
|
|
||||||
ndkVersion = flutter.ndkVersion
|
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
|
||||||
applicationId = "com.example.hym_ui"
|
|
||||||
// You can update the following values to match your application needs.
|
|
||||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
|
||||||
minSdk = flutter.minSdkVersion
|
|
||||||
targetSdk = flutter.targetSdkVersion
|
|
||||||
versionCode = flutterVersionCode.toInteger()
|
|
||||||
versionName = flutterVersionName
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTypes {
|
|
||||||
release {
|
|
||||||
// TODO: Add your own signing config for the release build.
|
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
|
||||||
signingConfig = signingConfigs.debug
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
flutter {
|
|
||||||
source = "../.."
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<!-- The INTERNET permission is required for development. Specifically,
|
|
||||||
the Flutter tool needs it to communicate with the running application
|
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
|
||||||
-->
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
|
||||||
</manifest>
|
|
@ -1,45 +0,0 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<application
|
|
||||||
android:label="hym_ui"
|
|
||||||
android:name="${applicationName}"
|
|
||||||
android:icon="@mipmap/ic_launcher">
|
|
||||||
<activity
|
|
||||||
android:name=".MainActivity"
|
|
||||||
android:exported="true"
|
|
||||||
android:launchMode="singleTop"
|
|
||||||
android:taskAffinity=""
|
|
||||||
android:theme="@style/LaunchTheme"
|
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
|
||||||
android:hardwareAccelerated="true"
|
|
||||||
android:windowSoftInputMode="adjustResize">
|
|
||||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
|
||||||
the Android process has started. This theme is visible to the user
|
|
||||||
while the Flutter UI initializes. After that, this theme continues
|
|
||||||
to determine the Window background behind the Flutter UI. -->
|
|
||||||
<meta-data
|
|
||||||
android:name="io.flutter.embedding.android.NormalTheme"
|
|
||||||
android:resource="@style/NormalTheme"
|
|
||||||
/>
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
<!-- Don't delete the meta-data below.
|
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
|
||||||
<meta-data
|
|
||||||
android:name="flutterEmbedding"
|
|
||||||
android:value="2" />
|
|
||||||
</application>
|
|
||||||
<!-- Required to query activities that can process text, see:
|
|
||||||
https://developer.android.com/training/package-visibility and
|
|
||||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
|
||||||
|
|
||||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
|
||||||
<queries>
|
|
||||||
<intent>
|
|
||||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
|
||||||
<data android:mimeType="text/plain"/>
|
|
||||||
</intent>
|
|
||||||
</queries>
|
|
||||||
</manifest>
|
|
@ -1,5 +0,0 @@
|
|||||||
package com.example.hym_ui
|
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
|
||||||
|
|
||||||
class MainActivity: FlutterActivity()
|
|
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Modify this file to customize your launch splash screen -->
|
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item android:drawable="?android:colorBackground" />
|
|
||||||
|
|
||||||
<!-- You can insert your own image assets here -->
|
|
||||||
<!-- <item>
|
|
||||||
<bitmap
|
|
||||||
android:gravity="center"
|
|
||||||
android:src="@mipmap/launch_image" />
|
|
||||||
</item> -->
|
|
||||||
</layer-list>
|
|
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Modify this file to customize your launch splash screen -->
|
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item android:drawable="@android:color/white" />
|
|
||||||
|
|
||||||
<!-- You can insert your own image assets here -->
|
|
||||||
<!-- <item>
|
|
||||||
<bitmap
|
|
||||||
android:gravity="center"
|
|
||||||
android:src="@mipmap/launch_image" />
|
|
||||||
</item> -->
|
|
||||||
</layer-list>
|
|
Before Width: | Height: | Size: 544 B |
Before Width: | Height: | Size: 442 B |
Before Width: | Height: | Size: 721 B |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.4 KiB |
@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
|
||||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
|
||||||
<!-- Show a splash screen on the activity. Automatically removed when
|
|
||||||
the Flutter engine draws its first frame -->
|
|
||||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
|
||||||
</style>
|
|
||||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
|
||||||
This theme determines the color of the Android Window while your
|
|
||||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
|
||||||
running.
|
|
||||||
|
|
||||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
|
||||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
|
||||||
<item name="android:windowBackground">?android:colorBackground</item>
|
|
||||||
</style>
|
|
||||||
</resources>
|
|
@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
|
||||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
|
||||||
<!-- Show a splash screen on the activity. Automatically removed when
|
|
||||||
the Flutter engine draws its first frame -->
|
|
||||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
|
||||||
</style>
|
|
||||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
|
||||||
This theme determines the color of the Android Window while your
|
|
||||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
|
||||||
running.
|
|
||||||
|
|
||||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
|
||||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
|
||||||
<item name="android:windowBackground">?android:colorBackground</item>
|
|
||||||
</style>
|
|
||||||
</resources>
|
|
@ -1,7 +0,0 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<!-- The INTERNET permission is required for development. Specifically,
|
|
||||||
the Flutter tool needs it to communicate with the running application
|
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
|
||||||
-->
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
|
||||||
</manifest>
|
|
@ -1,32 +0,0 @@
|
|||||||
buildscript {
|
|
||||||
ext.kotlin_version = '1.9.10'
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:8.3.0'
|
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rootProject.buildDir = "../build"
|
|
||||||
subprojects {
|
|
||||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
|
||||||
}
|
|
||||||
subprojects {
|
|
||||||
project.evaluationDependsOn(":app")
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register("clean", Delete) {
|
|
||||||
delete rootProject.buildDir
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError
|
|
||||||
android.useAndroidX=true
|
|
||||||
android.enableJetifier=true
|
|
@ -1,5 +0,0 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
|
||||||
distributionPath=wrapper/dists
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
|
|
@ -1,25 +0,0 @@
|
|||||||
pluginManagement {
|
|
||||||
def flutterSdkPath = {
|
|
||||||
def properties = new Properties()
|
|
||||||
file("local.properties").withInputStream { properties.load(it) }
|
|
||||||
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
|
||||||
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
|
||||||
return flutterSdkPath
|
|
||||||
}()
|
|
||||||
|
|
||||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
gradlePluginPortal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
|
||||||
id "com.android.application" version "7.3.0" apply false
|
|
||||||
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
|
|
||||||
}
|
|
||||||
|
|
||||||
include ":app"
|
|
@ -1,19 +0,0 @@
|
|||||||
import 'structs.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class SonicEmailView extends StatefulWidget {
|
|
||||||
SerializableMessage email;
|
|
||||||
String emailHTML;
|
|
||||||
|
|
||||||
SonicEmailView({required this.email, required this.emailHTML});
|
|
||||||
|
|
||||||
@override
|
|
||||||
_SonicEmailViewState createState() => _SonicEmailViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SonicEmailViewState extends State<SonicEmailView> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(body: Text("sonic email android"));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
import 'structs.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class SonicEmailView extends StatefulWidget {
|
|
||||||
SerializableMessage email;
|
|
||||||
String emailHTML;
|
|
||||||
|
|
||||||
SonicEmailView({required this.email, required this.emailHTML});
|
|
||||||
|
|
||||||
@override
|
|
||||||
_SonicEmailViewState createState() => _SonicEmailViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SonicEmailViewState extends State<SonicEmailView> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body:Text("sonic email stub")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,145 +0,0 @@
|
|||||||
import 'package:crab_ui/augment.dart';
|
|
||||||
import 'package:web/web.dart' as web;
|
|
||||||
import 'dart:ui_web' as ui;
|
|
||||||
import 'dart:js_interop';
|
|
||||||
import 'structs.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class SonicEmailView extends StatefulWidget {
|
|
||||||
SerializableMessage email;
|
|
||||||
String emailHTML;
|
|
||||||
|
|
||||||
SonicEmailView({required this.email, required this.emailHTML});
|
|
||||||
|
|
||||||
@override
|
|
||||||
_SonicEmailViewState createState() => _SonicEmailViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SonicEmailViewState extends State<SonicEmailView> {
|
|
||||||
String viewTypeIDs = "";
|
|
||||||
int heightOFViewtype = 0;
|
|
||||||
bool _isLoaded = false;
|
|
||||||
|
|
||||||
void _scrollToNumber(String spanId) {
|
|
||||||
AugmentClasses.handleJump(spanId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _init() async {
|
|
||||||
await _registerViewFactory(widget.emailHTML);
|
|
||||||
if (!mounted) return;
|
|
||||||
setState(() {
|
|
||||||
_isLoaded = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _registerViewFactory(String currentContent) async {
|
|
||||||
// setState(() { //update to do item per item
|
|
||||||
// each item to have itsviewtype ID
|
|
||||||
// is this necessarey here??
|
|
||||||
|
|
||||||
//could just move to collapsable
|
|
||||||
|
|
||||||
// for (var emailHTML in widget.threadHTML) {
|
|
||||||
String viewTypeId = 'email-${DateTime.now().millisecondsSinceEpoch}';
|
|
||||||
|
|
||||||
final ghost = web.document.createElement('div') as web.HTMLDivElement
|
|
||||||
..style.visibility = 'hidden'
|
|
||||||
..style.position = 'absolute'
|
|
||||||
..style.width = '100%'
|
|
||||||
..style.overflow = 'auto'
|
|
||||||
..innerHTML = currentContent.toJS;
|
|
||||||
web.document.body?.append(ghost);
|
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
|
||||||
|
|
||||||
final heightOfEmail = ghost.scrollHeight;
|
|
||||||
ghost.remove();
|
|
||||||
|
|
||||||
final HTMLsnippet = web.document.createElement('div') as web.HTMLDivElement
|
|
||||||
..id = viewTypeId
|
|
||||||
..innerHTML = widget
|
|
||||||
.emailHTML.toJS; // temporarily index because it has to do all of them
|
|
||||||
HTMLsnippet.style
|
|
||||||
..width = '100%'
|
|
||||||
..height = '${heightOfEmail}px'
|
|
||||||
..overflow = 'auto'
|
|
||||||
..scrollBehavior = 'smooth';
|
|
||||||
|
|
||||||
ui.platformViewRegistry.registerViewFactory(
|
|
||||||
viewTypeId,
|
|
||||||
(int viewId) => HTMLsnippet,
|
|
||||||
);
|
|
||||||
this.viewTypeIDs = viewTypeId;
|
|
||||||
this.heightOFViewtype = heightOfEmail;
|
|
||||||
print(viewTypeIDs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return _isLoaded
|
|
||||||
? Scaffold(
|
|
||||||
appBar: AppBar(title: Text(widget.email.subject)),
|
|
||||||
body: Stack(
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
EmailToolbar(
|
|
||||||
onButtonPressed: () => {},
|
|
||||||
onJumpToSpan: _scrollToNumber),
|
|
||||||
Row(
|
|
||||||
// title of email
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
widget.email.subject,
|
|
||||||
style: TextStyle(fontSize: 30),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'from ${widget.email.name}',
|
|
||||||
style: TextStyle(fontSize: 18),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'<${widget.email.from}>',
|
|
||||||
style: TextStyle(fontSize: 18),
|
|
||||||
),
|
|
||||||
Spacer(),
|
|
||||||
Text(
|
|
||||||
'${widget.email.date}',
|
|
||||||
textAlign: TextAlign.right,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
// TODO: make a case where if one of these is the user's email it just says me :)))))
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'to ${widget.email.to.toString()}',
|
|
||||||
style: TextStyle(fontSize: 15),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
// child: SizedBox(
|
|
||||||
// height: heightOFViewtype.toDouble(),
|
|
||||||
child: HtmlElementView(
|
|
||||||
key: UniqueKey(), viewType: this.viewTypeIDs,
|
|
||||||
// ),
|
|
||||||
))
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,12 +4,19 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||||
|
import 'collapsableEmails.dart';
|
||||||
|
|
||||||
import 'structs.dart';
|
import 'structs.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:ui_web' as ui;
|
||||||
|
import 'augment.dart';
|
||||||
|
// import 'dart:html' as html;
|
||||||
|
// import 'dart:js' as js;
|
||||||
|
import 'package:web/web.dart' as web;
|
||||||
|
import 'dart:js_interop' as js;
|
||||||
|
|
||||||
class ApiService {
|
class ApiService {
|
||||||
static String ip = "";
|
static String ip = "";
|
||||||
@ -415,4 +422,237 @@ class ApiService {
|
|||||||
|
|
||||||
// return [];
|
// return [];
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EmailView extends StatefulWidget {
|
||||||
|
final List<String> emailContent;
|
||||||
|
final String from;
|
||||||
|
final String name;
|
||||||
|
final String to;
|
||||||
|
final String subject;
|
||||||
|
final String date;
|
||||||
|
final String id;
|
||||||
|
final List<String> messages;
|
||||||
|
|
||||||
|
const EmailView({
|
||||||
|
Key? key,
|
||||||
|
required this.emailContent,
|
||||||
|
required this.from,
|
||||||
|
required this.name,
|
||||||
|
required this.to,
|
||||||
|
required this.subject,
|
||||||
|
required this.date,
|
||||||
|
required this.id,
|
||||||
|
required this.messages,
|
||||||
|
}) : super(key: key);
|
||||||
|
@override
|
||||||
|
_EmailViewState createState() => _EmailViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EmailViewState extends State<EmailView> {
|
||||||
|
//html css rendering thing
|
||||||
|
late Key iframeKey;
|
||||||
|
late String currentContent;
|
||||||
|
late String viewTypeId; //make this a list too???
|
||||||
|
Future<List<Map<String, dynamic>>>? _markerPositionsFuture;
|
||||||
|
// TextEditingController _jumpController = TextEditingController();
|
||||||
|
final hardcodedMarkers = [
|
||||||
|
{'id': 'marker1', 'x': 50, 'y': 100},
|
||||||
|
{'id': 'marker2', 'x': 150, 'y': 200},
|
||||||
|
{'id': 'marker3', 'x': 250, 'y': 300},
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
print("thread id? ${widget.id}");
|
||||||
|
List<String> currentContent = widget
|
||||||
|
.emailContent; //html of the email/ actually entire thread, gives me little space to play in between
|
||||||
|
// i wonder if the other attributes change? because if so i have to add like some zooms in and out of the emails, as in collapse
|
||||||
|
// _registerViewFactory(currentContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void _registerViewFactory(List<String> currentContent) { // i think this doesnt work anymore
|
||||||
|
// setState(() { //update to do item per item
|
||||||
|
// // each item to have itsviewtype ID
|
||||||
|
// // is this necessarey here??
|
||||||
|
|
||||||
|
// //could just move to collapsable
|
||||||
|
|
||||||
|
// viewTypeId = 'iframe-${DateTime.now().millisecondsSinceEpoch}';
|
||||||
|
// final emailHTML = web.document.createElement('div') as web.HTMLDivElement
|
||||||
|
// ..id = viewTypeId
|
||||||
|
// ..innerHTML = currentContent[0].toJS; // temporarily index because it has to do all of them
|
||||||
|
// emailHTML.style
|
||||||
|
// ..width = '100%'
|
||||||
|
// ..height = '100%'
|
||||||
|
// ..overflow = 'auto'
|
||||||
|
// ..scrollBehavior = 'smooth';
|
||||||
|
|
||||||
|
// ui.platformViewRegistry.registerViewFactory(
|
||||||
|
// viewTypeId,
|
||||||
|
// (int viewId) => emailHTML,
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
void _scrollToNumber(String spanId) {
|
||||||
|
AugmentClasses.handleJump(spanId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: void _invisibility(String ) //to make purple numbers not visible
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
// print("thread id ${widget.id}");
|
||||||
|
ApiService.currThreadID = widget.id;
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(widget.name),
|
||||||
|
),
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
EmailToolbar(
|
||||||
|
onJumpToSpan: _scrollToNumber,
|
||||||
|
onButtonPressed: () => {},
|
||||||
|
// AugmentClasses.handleJump(viewTypeId, '1');
|
||||||
|
// print("button got pressed?");
|
||||||
|
|
||||||
|
// _registerViewFactory(r"""
|
||||||
|
// <h1>Welcome to My Website</h1>
|
||||||
|
// <p>This is a simple HTML page.</p>
|
||||||
|
// <h2>What is HTML?</h2>
|
||||||
|
// <p>HTML (HyperText Markup Language) is the most basic building~ block of the Web. It defines the meaning and structure of web content. Other technologies besides HTML are generally used to describe a web page's appearance/presentation (CSS) or functionality/behavior (JavaScript).</p>
|
||||||
|
// <h3>Here's a simple list:</h3>
|
||||||
|
// <ul>
|
||||||
|
// <li>HTML elements are the building blocks of HTML pages</li>
|
||||||
|
// <li>HTML uses tags like <code><tag></code> to organize and format content</li>
|
||||||
|
// <li>CSS is used with HTML to style pages</li>
|
||||||
|
// </ul>
|
||||||
|
// <p>Copyright © 2023</p>
|
||||||
|
// """);
|
||||||
|
// print("change");
|
||||||
|
// widget.emailContent = r"
|
||||||
|
|
||||||
|
//
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
// title of email
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
widget.subject,
|
||||||
|
style: TextStyle(fontSize: 30),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'from ${widget.name}',
|
||||||
|
style: TextStyle(fontSize: 18),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'<${widget.from}>',
|
||||||
|
style: TextStyle(fontSize: 18),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
Text(
|
||||||
|
'${widget.date}',
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// TODO: make a case where if one of these is the user's email it just says me :)))))
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'to ${widget.to.toString()}',
|
||||||
|
style: TextStyle(fontSize: 15),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: CollapsableEmails(
|
||||||
|
//change here
|
||||||
|
thread: widget.messages, //this wont work in serializable
|
||||||
|
threadHTML: widget.emailContent,
|
||||||
|
threadIDs: widget.id,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Expanded(
|
||||||
|
// child: HtmlElementView(
|
||||||
|
// key: UniqueKey(),
|
||||||
|
// viewType: viewTypeId,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
// Overlay widgets dynamically based on marker positions
|
||||||
|
// FutureBuilder<List<Map<String, dynamic>>>(
|
||||||
|
// future: _markerPositionsFuture,
|
||||||
|
// builder: (context, snapshot) {
|
||||||
|
// print("FutureBuilder state: ${snapshot.connectionState}");
|
||||||
|
// if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
// return Center(child: CircularProgressIndicator());
|
||||||
|
// }
|
||||||
|
// if (snapshot.hasError) {
|
||||||
|
// print("Error in FutureBuilder: ${snapshot.error}");
|
||||||
|
// return Center(child: Text('error loading markers'));
|
||||||
|
// }
|
||||||
|
// if (snapshot.hasData && snapshot.data != null) {
|
||||||
|
// final markers = snapshot.data!;
|
||||||
|
// return Stack(
|
||||||
|
// children: markers.map((marker) {
|
||||||
|
// return Positioned(
|
||||||
|
// left: marker['x'].toDouble(),
|
||||||
|
// top: marker['y'].toDouble(),
|
||||||
|
// child: GestureDetector(
|
||||||
|
// onTap: () {
|
||||||
|
// print('Tapped on ${marker['id']}');
|
||||||
|
// },
|
||||||
|
// child: Container(
|
||||||
|
// width: 50,
|
||||||
|
// height: 50,
|
||||||
|
// color: Colors.red,
|
||||||
|
// child: Center(
|
||||||
|
// child: Text(
|
||||||
|
// marker['id'],
|
||||||
|
// style: TextStyle(color: Colors.white),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }).toList(),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return SizedBox.shrink(); // No markers found
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// Red widget overlay
|
||||||
|
// Positioned(
|
||||||
|
// left: 8, // Adjust based on your desired position
|
||||||
|
// top: 100 + 44 + 5, // Adjust based on your desired position
|
||||||
|
// child: IgnorePointer(
|
||||||
|
// ignoring: true, // Ensures the iframe remains interactive
|
||||||
|
// child: Container(
|
||||||
|
// color: Colors.red,
|
||||||
|
// width: 100,
|
||||||
|
// height: 50,
|
||||||
|
// child: Center(
|
||||||
|
// child: Text(
|
||||||
|
// 'Overlay',
|
||||||
|
// style: TextStyle(color: Colors.white),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
import 'structs.dart';
|
|
||||||
|
|
||||||
class Attachmentdownload {
|
|
||||||
Future<void> saveFile(AttachmentResponse attachment) async {
|
|
||||||
print("stub attachment download");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +1,15 @@
|
|||||||
export 'attachamentDownloadStub.dart'
|
import 'dart:html' as html;
|
||||||
if (dart.library.io) 'attachmentDownloadAndroid.dart';
|
import 'package:web/web.dart' as web;
|
||||||
// if (dart.library.js_interop) 'attachmentDownloadWeb.dart';
|
import 'dart:io';
|
||||||
|
import 'structs.dart';
|
||||||
|
import 'package:file_saver/file_saver.dart';
|
||||||
|
|
||||||
|
class Attachmentdownload {
|
||||||
|
Future<void> saveFile(AttachmentResponse attachment) async {
|
||||||
|
await FileSaver.instance.saveFile(
|
||||||
|
name: attachment.name.toString().substring(0, attachment.name.toString().lastIndexOf('.')),
|
||||||
|
bytes: attachment.data,
|
||||||
|
ext: attachment.name.toString().substring(attachment.name.toString().lastIndexOf('.')+1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
import 'structs.dart';
|
|
||||||
|
|
||||||
class Attachmentdownload {
|
|
||||||
Future<void> saveFile(AttachmentResponse attachment) async {
|
|
||||||
print("android attachment download");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
// import 'structs.dart';
|
|
||||||
// import 'package:file_saver/file_saver.dart';
|
|
||||||
|
|
||||||
// class Attachmentdownload {
|
|
||||||
// Future<void> saveFile(AttachmentResponse attachment) async {
|
|
||||||
// await FileSaver.instance.saveFile(
|
|
||||||
// name: attachment.name.toString().substring(0, attachment.name.toString().lastIndexOf('.')),
|
|
||||||
// bytes: attachment.data,
|
|
||||||
// ext: attachment.name.toString().substring(attachment.name.toString().lastIndexOf('.')+1)
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
@ -1,3 +1,103 @@
|
|||||||
export 'attachmentWidgetStub.dart'
|
import "dart:typed_data";
|
||||||
if (dart.library.js_interop) 'attachmentWidgetWeb.dart'
|
|
||||||
if (dart.library.io) 'attachmentWidgetAndroid.dart';
|
import "package:crab_ui/attachmentDownload.dart";
|
||||||
|
import "package:crab_ui/structs.dart";
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
import 'package:pdfrx/pdfrx.dart';
|
||||||
|
import 'package:photo_view/photo_view.dart';
|
||||||
|
|
||||||
|
class AttachmentWidget extends StatelessWidget {
|
||||||
|
final AttachmentResponse attachment;
|
||||||
|
AttachmentWidget({required this.attachment});
|
||||||
|
|
||||||
|
Widget attachmentViewer(AttachmentResponse att) {
|
||||||
|
String extension = att.name
|
||||||
|
.toString()
|
||||||
|
.substring(att.name.toString().indexOf(".") + 1)
|
||||||
|
.toLowerCase();
|
||||||
|
if (extension == "jpg" || extension == "png") {
|
||||||
|
return Image.memory(att.data);
|
||||||
|
} else if (extension == "pdf") {
|
||||||
|
return PdfViewer.data(Uint8List.fromList(att.data),
|
||||||
|
sourceName: att.name,
|
||||||
|
params: PdfViewerParams(
|
||||||
|
enableTextSelection: true,
|
||||||
|
scrollByMouseWheel: 0.5,
|
||||||
|
annotationRenderingMode:
|
||||||
|
PdfAnnotationRenderingMode.annotationAndForms,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return Center(
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.all(20),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Color(0xff6C63FF),
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black26,
|
||||||
|
blurRadius: 10,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"No preview available",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white, fontSize: 18, decoration: TextDecoration.none),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 5,
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
child: ElevatedButton(
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text("Download", style: TextStyle(color: Color(0xff2c3e50)),),
|
||||||
|
Icon(Icons.download,
|
||||||
|
color: Color(0xffb0b0b0),),
|
||||||
|
]),
|
||||||
|
onPressed: () => Attachmentdownload().saveFile(att),
|
||||||
|
)),
|
||||||
|
]),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
color: Colors.black38,
|
||||||
|
child: Stack(children: <Widget>[
|
||||||
|
Container(
|
||||||
|
color: Colors.white,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(10, 20, 0, 10),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
CloseButton(onPressed: () => {Navigator.pop(context)}),
|
||||||
|
Text(
|
||||||
|
attachment.name
|
||||||
|
.toString(), //its alr a string but incase ¯\(ツ)/¯ //update: i did that everywhere lol
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 20,
|
||||||
|
decoration: TextDecoration
|
||||||
|
.none), //TODO: personalize your fonts
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: attachmentViewer(attachment),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
import "package:crab_ui/structs.dart";
|
|
||||||
import "package:flutter/material.dart";
|
|
||||||
|
|
||||||
|
|
||||||
class AttachmentWidget extends StatelessWidget {
|
|
||||||
final AttachmentResponse attachment;
|
|
||||||
AttachmentWidget({required this.attachment});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body: Text("PDF EVENTUALLY ANDROID")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'structs.dart';
|
|
||||||
|
|
||||||
class AttachmentWidget extends StatelessWidget{
|
|
||||||
final AttachmentResponse attachment;
|
|
||||||
AttachmentWidget({required this.attachment});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body: Text("PDF EVENTUALLY, STUB")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,101 +0,0 @@
|
|||||||
import "dart:typed_data";
|
|
||||||
import "package:crab_ui/attachmentDownload.dart";
|
|
||||||
import "package:crab_ui/structs.dart";
|
|
||||||
import "package:flutter/material.dart";
|
|
||||||
import 'package:pdfrx/pdfrx.dart';
|
|
||||||
|
|
||||||
class AttachmentWidget extends StatelessWidget {
|
|
||||||
final AttachmentResponse attachment;
|
|
||||||
AttachmentWidget({required this.attachment});
|
|
||||||
|
|
||||||
Widget attachmentViewer(AttachmentResponse att) {
|
|
||||||
String extension = att.name
|
|
||||||
.toString()
|
|
||||||
.substring(att.name.toString().indexOf(".") + 1)
|
|
||||||
.toLowerCase();
|
|
||||||
if (extension == "jpg" || extension == "png") {
|
|
||||||
return Image.memory(att.data);
|
|
||||||
} else if (extension == "pdf") {
|
|
||||||
return PdfViewer.data(Uint8List.fromList(att.data),
|
|
||||||
sourceName: att.name,
|
|
||||||
params: PdfViewerParams(
|
|
||||||
enableTextSelection: true,
|
|
||||||
scrollByMouseWheel: 0.5,
|
|
||||||
annotationRenderingMode:
|
|
||||||
PdfAnnotationRenderingMode.annotationAndForms,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return Center(
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.all(20),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Color(0xff6C63FF),
|
|
||||||
borderRadius: BorderRadius.circular(16),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black26,
|
|
||||||
blurRadius: 10,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"No preview available",
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white, fontSize: 18, decoration: TextDecoration.none),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 5,
|
|
||||||
),
|
|
||||||
GestureDetector(
|
|
||||||
child: ElevatedButton(
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Text("Download", style: TextStyle(color: Color(0xff2c3e50)),),
|
|
||||||
Icon(Icons.download,
|
|
||||||
color: Color(0xffb0b0b0),),
|
|
||||||
]),
|
|
||||||
onPressed: () => Attachmentdownload().saveFile(att),
|
|
||||||
)),
|
|
||||||
]),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
color: Colors.black38,
|
|
||||||
child: Stack(children: <Widget>[
|
|
||||||
Container(
|
|
||||||
color: Colors.white,
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.fromLTRB(10, 20, 0, 10),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
CloseButton(onPressed: () => {Navigator.pop(context)}),
|
|
||||||
Text(
|
|
||||||
attachment.name
|
|
||||||
.toString(), //its alr a string but incase ¯\(ツ)/¯ //update: i did that everywhere lol
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.black,
|
|
||||||
fontSize: 20,
|
|
||||||
decoration: TextDecoration
|
|
||||||
.none), //TODO: personalize your fonts
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: attachmentViewer(attachment),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,14 @@
|
|||||||
|
// import 'dart:ffi';
|
||||||
|
|
||||||
import 'package:crab_ui/api_service.dart';
|
import 'package:crab_ui/api_service.dart';
|
||||||
import 'package:crab_ui/attachmentDownload.dart';
|
import 'package:crab_ui/attachmentDownload.dart';
|
||||||
import 'package:crab_ui/structs.dart';
|
import 'package:crab_ui/structs.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pdfrx/pdfrx.dart';
|
||||||
|
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||||
|
// import 'dart:html' as html;
|
||||||
|
// import 'dart:js' as js;
|
||||||
|
import 'package:web/web.dart' as web;
|
||||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||||
import 'attachmentWidget.dart';
|
import 'attachmentWidget.dart';
|
||||||
|
|
||||||
|
@ -1,3 +1,132 @@
|
|||||||
export 'collapsableEmailsStub.dart'
|
import 'dart:js_interop';
|
||||||
if (dart.library.io) 'collapsableEmailsAndroid.dart'
|
import 'package:web/web.dart' as web;
|
||||||
if (dart.library.js_interop) 'collapsableEmailsWeb.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:ui_web' as ui;
|
||||||
|
import 'api_service.dart';
|
||||||
|
import 'structs.dart';
|
||||||
|
|
||||||
|
class CollapsableEmails extends StatefulWidget {
|
||||||
|
final List<String> thread; // email id's in the form xyz@gmail.com
|
||||||
|
final List<String> threadHTML;
|
||||||
|
final String threadIDs;
|
||||||
|
|
||||||
|
CollapsableEmails(
|
||||||
|
{required this.thread,
|
||||||
|
required this.threadHTML,
|
||||||
|
required this.threadIDs});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CollapsableEmails> createState() => _CollapsableEmailsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CollapsableEmailsState extends State<CollapsableEmails> {
|
||||||
|
List<String> emailsHTML = []; //html of the emails in the thread
|
||||||
|
// build attachments with the forldar name and id
|
||||||
|
Set<int> _expandedEmails = {}; //open emails
|
||||||
|
List viewtypeIDs = []; //IDs of the viewtypes, order matters
|
||||||
|
List heightOfViewTypes = []; //the height of each viewtype
|
||||||
|
List<SerializableMessage> emailsInThread = [];
|
||||||
|
bool _isLoaded = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
// TODO: implement initState
|
||||||
|
super.initState();
|
||||||
|
_registerViewFactory(widget.threadHTML);
|
||||||
|
_serializableData(widget.threadIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _registerViewFactory(List<String> currentContent) async {
|
||||||
|
// setState(() { //update to do item per item
|
||||||
|
// each item to have itsviewtype ID
|
||||||
|
// is this necessarey here??
|
||||||
|
|
||||||
|
//could just move to collapsable
|
||||||
|
|
||||||
|
for (var emailHTML in widget.threadHTML) {
|
||||||
|
String viewTypeId = 'email-${DateTime.now().millisecondsSinceEpoch}';
|
||||||
|
|
||||||
|
final ghost = web.document.createElement('div') as web.HTMLDivElement
|
||||||
|
..style.visibility = 'hidden'
|
||||||
|
..style.position = 'absolute'
|
||||||
|
..style.width = '100%'
|
||||||
|
..style.overflow = 'auto'
|
||||||
|
..innerHTML = emailHTML
|
||||||
|
.toJS; // temporarily index because it has to do all of them
|
||||||
|
web.document.body?.append(ghost);
|
||||||
|
await Future.delayed(Duration(milliseconds: 10));
|
||||||
|
|
||||||
|
final heightOfEmail = ghost.scrollHeight;
|
||||||
|
ghost.remove();
|
||||||
|
|
||||||
|
final HTMLsnippet = web.document.createElement('div')
|
||||||
|
as web.HTMLDivElement
|
||||||
|
..id = viewTypeId
|
||||||
|
..innerHTML = emailHTML
|
||||||
|
.toJS; // temporarily index because it has to do all of them
|
||||||
|
HTMLsnippet.style
|
||||||
|
..width = '100%'
|
||||||
|
..height = '${heightOfEmail}px'
|
||||||
|
..overflow = 'auto'
|
||||||
|
..scrollBehavior = 'smooth';
|
||||||
|
|
||||||
|
ui.platformViewRegistry.registerViewFactory(
|
||||||
|
viewTypeId,
|
||||||
|
(int viewId) => HTMLsnippet,
|
||||||
|
);
|
||||||
|
viewtypeIDs.add(viewTypeId);
|
||||||
|
heightOfViewTypes.add(heightOfEmail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _serializableData(String threadID) async {
|
||||||
|
emailsInThread = await ApiService().threadsInSerializable(threadID);
|
||||||
|
print("done thread serializable");
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() {
|
||||||
|
_isLoaded = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return _isLoaded
|
||||||
|
?Column(children: [
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: widget.thread.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final isExpanded =
|
||||||
|
_expandedEmails.contains(index); //check if email is expanded
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
title: Text(emailsInThread[index].from),
|
||||||
|
trailing: Text(emailsInThread[index].date),
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
if (isExpanded) {
|
||||||
|
_expandedEmails.remove(index);
|
||||||
|
} else {
|
||||||
|
_expandedEmails.add(index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (isExpanded)
|
||||||
|
// if(viewtypeIDs[index] == null || heightOfViewTypes[index] == null)
|
||||||
|
// const SizedBox(height: 100, child: Center(child: CircularProgressIndicator())),
|
||||||
|
SizedBox(
|
||||||
|
height: heightOfViewTypes[index].toDouble(),
|
||||||
|
child: HtmlElementView(
|
||||||
|
key: UniqueKey(), viewType: viewtypeIDs[index]),
|
||||||
|
),
|
||||||
|
Divider(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]): const Center(child:CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
import 'structs.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
|
||||||
|
|
||||||
class CollapsableEmails extends StatefulWidget {
|
|
||||||
final List<String> thread; // email id's in the form xyz@gmail.com
|
|
||||||
final List<String> threadHTML;
|
|
||||||
final String threadIDs;
|
|
||||||
|
|
||||||
CollapsableEmails(
|
|
||||||
{required this.thread,
|
|
||||||
required this.threadHTML,
|
|
||||||
required this.threadIDs});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<CollapsableEmails> createState() => _CollapsableEmailsState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CollapsableEmailsState extends State<CollapsableEmails> {
|
|
||||||
List<String> emailsHTML = []; //html of the emails in the thread
|
|
||||||
// build attachments with the forldar name and id
|
|
||||||
Set<int> _expandedEmails = {}; //open emails
|
|
||||||
List viewtypeIDs = []; //IDs of the viewtypes, order matters
|
|
||||||
List heightOfViewTypes = []; //the height of each viewtype
|
|
||||||
List<SerializableMessage> emailsInThread = [];
|
|
||||||
bool _isLoaded = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
//html
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body: ListView(
|
|
||||||
children: [
|
|
||||||
HtmlWidget(
|
|
||||||
widget.threadHTML[0],
|
|
||||||
// renderMode: RenderMode.listView,
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
import 'structs.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class CollapsableEmails extends StatefulWidget {
|
|
||||||
final List<String> thread; // email id's in the form xyz@gmail.com
|
|
||||||
final List<String> threadHTML;
|
|
||||||
final String threadIDs;
|
|
||||||
|
|
||||||
CollapsableEmails(
|
|
||||||
{required this.thread,
|
|
||||||
required this.threadHTML,
|
|
||||||
required this.threadIDs});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<CollapsableEmails> createState() => _CollapsableEmailsState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CollapsableEmailsState extends State<CollapsableEmails> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(body: Text("collapsable stud"));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,255 +0,0 @@
|
|||||||
import 'dart:js_interop';
|
|
||||||
import 'dart:js_interop_unsafe';
|
|
||||||
import 'package:web/web.dart' as web;
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'dart:ui_web' as ui;
|
|
||||||
import 'api_service.dart';
|
|
||||||
import 'structs.dart';
|
|
||||||
|
|
||||||
class CollapsableEmails extends StatefulWidget {
|
|
||||||
final List<String> thread; // email id's in the form xyz@gmail.com
|
|
||||||
final List<String> threadHTML;
|
|
||||||
final String threadIDs;
|
|
||||||
|
|
||||||
CollapsableEmails(
|
|
||||||
{required this.thread,
|
|
||||||
required this.threadHTML,
|
|
||||||
required this.threadIDs});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<CollapsableEmails> createState() => _CollapsableEmailsState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CollapsableEmailsState extends State<CollapsableEmails> {
|
|
||||||
List<String> emailsHTML = []; //html of the emails in the thread
|
|
||||||
// build attachments with the forldar name and id
|
|
||||||
Set<int> _expandedEmails = {}; //open emails
|
|
||||||
List viewtypeIDs = []; //IDs of the viewtypes, order matters
|
|
||||||
List heightOfViewTypes = []; //the height of each viewtype
|
|
||||||
List<SerializableMessage> emailsInThread = [];
|
|
||||||
bool _isLoaded = false;
|
|
||||||
static bool _isListenerRegistered = false;
|
|
||||||
static bool left = true;
|
|
||||||
static bool right = true;
|
|
||||||
web.EventListener? _listener;
|
|
||||||
List<String> hirarchy = ["h1", "h2", "h3", "h4", "h5", "h6", "p"];
|
|
||||||
List<String> tagsCollected = [];
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_registerViewFactory(widget.threadHTML);
|
|
||||||
_serializableData(widget.threadIDs); // this
|
|
||||||
_keyListener();
|
|
||||||
}
|
|
||||||
// @override
|
|
||||||
// void dispose() {
|
|
||||||
// if (_listener != null) {
|
|
||||||
// web.window.document.removeEventListener('keydown', _listener!);
|
|
||||||
// }
|
|
||||||
// super.dispose();
|
|
||||||
// }
|
|
||||||
|
|
||||||
void _registerViewFactory(List<String> currentContent) async {
|
|
||||||
// setState(() { //update to do item per item
|
|
||||||
// each item to have itsviewtype ID
|
|
||||||
// is this necessarey here??
|
|
||||||
|
|
||||||
//could just move to collapsable
|
|
||||||
|
|
||||||
for (var emailHTML in widget.threadHTML) {
|
|
||||||
String viewTypeId = 'email-${DateTime.now().millisecondsSinceEpoch}';
|
|
||||||
|
|
||||||
final ghost = web.document.createElement('div') as web.HTMLDivElement
|
|
||||||
..style.visibility = 'hidden'
|
|
||||||
..style.position = 'absolute'
|
|
||||||
..style.width = '100%'
|
|
||||||
..style.overflow = 'auto'
|
|
||||||
..innerHTML = emailHTML
|
|
||||||
.toJS; // temporarily index because it has to do all of them
|
|
||||||
web.document.body?.append(ghost);
|
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
|
||||||
|
|
||||||
final heightOfEmail = ghost.scrollHeight;
|
|
||||||
ghost.remove();
|
|
||||||
|
|
||||||
final HTMLsnippet = web.document.createElement('div')
|
|
||||||
as web.HTMLDivElement
|
|
||||||
..id = viewTypeId
|
|
||||||
..innerHTML = emailHTML
|
|
||||||
.toJS; // temporarily index because it has to do all of them
|
|
||||||
HTMLsnippet.style
|
|
||||||
..width = '100%'
|
|
||||||
..height = '${heightOfEmail}px'
|
|
||||||
..overflow = 'auto'
|
|
||||||
..scrollBehavior = 'smooth';
|
|
||||||
|
|
||||||
ui.platformViewRegistry.registerViewFactory(
|
|
||||||
viewTypeId,
|
|
||||||
(int viewId) => HTMLsnippet,
|
|
||||||
);
|
|
||||||
viewtypeIDs.add(viewTypeId);
|
|
||||||
heightOfViewTypes.add(heightOfEmail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _serializableData(String threadID) async {
|
|
||||||
emailsInThread = await ApiService().threadsInSerializable(threadID);
|
|
||||||
print("done thread serializable");
|
|
||||||
if (!mounted) return;
|
|
||||||
setState(() {
|
|
||||||
_isLoaded = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleKeyDown(web.Event event) {
|
|
||||||
final keyEvent = event as web.KeyboardEvent;
|
|
||||||
|
|
||||||
if (keyEvent.key == 'G') {
|
|
||||||
print('You pressed the "G" key!');
|
|
||||||
final rightPurpleNums = web.document.getElementsByClassName("right");
|
|
||||||
_CollapsableEmailsState.right = !_CollapsableEmailsState.right;
|
|
||||||
final newOpacity = _CollapsableEmailsState.right ? '1.0' : '0.0';
|
|
||||||
for (int i = 0; i < rightPurpleNums.length; i++) {
|
|
||||||
final currentElement = rightPurpleNums.item(i) as web.HTMLElement;
|
|
||||||
currentElement.style.opacity = newOpacity;
|
|
||||||
}
|
|
||||||
} else if (keyEvent.key == 'H') {
|
|
||||||
print('You pressed the "H" key!');
|
|
||||||
final leftPurpleNums = web.document.getElementsByClassName("left");
|
|
||||||
_CollapsableEmailsState.left = !_CollapsableEmailsState.left;
|
|
||||||
final newOpacity = _CollapsableEmailsState.left ? '1.0' : '0.0';
|
|
||||||
for (int i = 0; i < leftPurpleNums.length; i++) {
|
|
||||||
final currentElement = leftPurpleNums.item(i) as web.HTMLElement;
|
|
||||||
currentElement.style.opacity = newOpacity;
|
|
||||||
}
|
|
||||||
} else if (keyEvent.key == 'm') {
|
|
||||||
print("you pressed 'm'");
|
|
||||||
final purpleNums = web.document.getElementsByClassName("purplenumber");
|
|
||||||
_CollapsableEmailsState.left = true;
|
|
||||||
_CollapsableEmailsState.right = true;
|
|
||||||
|
|
||||||
for (int i = 0; i < purpleNums.length; i++) {
|
|
||||||
final currentElement = purpleNums.item(i) as web.HTMLElement;
|
|
||||||
currentElement.style.opacity = '1.0';
|
|
||||||
}
|
|
||||||
} else if (keyEvent.key == 'n') {
|
|
||||||
print("you pressed 'n'");
|
|
||||||
final purpleNums = web.document.getElementsByClassName("purplenumber");
|
|
||||||
_CollapsableEmailsState.left = false;
|
|
||||||
_CollapsableEmailsState.right = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < purpleNums.length; i++) {
|
|
||||||
final currentElement = purpleNums.item(i) as web.HTMLElement;
|
|
||||||
currentElement.style.opacity = '0.0';
|
|
||||||
}
|
|
||||||
} else if (keyEvent.key == 'w') {
|
|
||||||
print("you pressed 'w'");
|
|
||||||
getTopLevel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _keyListener() {
|
|
||||||
if (_isListenerRegistered) return;
|
|
||||||
_isListenerRegistered = true;
|
|
||||||
|
|
||||||
// Convert the top-level function to JS-compatible
|
|
||||||
_listener = handleKeyDown.toJS;
|
|
||||||
web.window.document.addEventListener('keydown', _listener!);
|
|
||||||
}
|
|
||||||
|
|
||||||
void getTopLevel() {
|
|
||||||
print("started top");
|
|
||||||
int highest = 0;
|
|
||||||
AugmentTree zoomTreeRoot = AugmentTree();
|
|
||||||
// zoomTreeRoot.data = emailsHTML[0]; // whole thing
|
|
||||||
|
|
||||||
while (highest < hirarchy.length - 1) {
|
|
||||||
var highestElement = web.document.querySelectorAll(hirarchy[highest]);
|
|
||||||
print("nodelist $highestElement");
|
|
||||||
|
|
||||||
if (highestElement.isNull || highestElement.length == 0) {
|
|
||||||
//from h1, h2, h3, ..., p.
|
|
||||||
highest += 1;
|
|
||||||
print(hirarchy[highest]);
|
|
||||||
} else {
|
|
||||||
AugmentTree newLevel = AugmentTree(); // list of children of each level
|
|
||||||
for (int i = 0; i < highestElement.length; i++) {
|
|
||||||
print(highestElement.item(i)?.textContent);
|
|
||||||
|
|
||||||
tagsCollected
|
|
||||||
.add(highestElement.item(i)?.textContent ?? "nameless subtitle");
|
|
||||||
newLevel.children
|
|
||||||
.add(highestElement.item(i)?.textContent ?? "nameless subtitle");
|
|
||||||
}
|
|
||||||
// traverse to last node and add new level to it
|
|
||||||
// next
|
|
||||||
if (zoomTreeRoot.node == null) {
|
|
||||||
zoomTreeRoot.node = newLevel;
|
|
||||||
} else {
|
|
||||||
AugmentTree temp = zoomTreeRoot;
|
|
||||||
while (true) {
|
|
||||||
//get to the last and assign node = last node
|
|
||||||
if (temp.node != null) {
|
|
||||||
temp = temp.node!;
|
|
||||||
} else {
|
|
||||||
temp.node = newLevel;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
highest += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
print("out safely");
|
|
||||||
print(tagsCollected); //instead of a list make a tree
|
|
||||||
print(zoomTreeRoot.children);
|
|
||||||
print(zoomTreeRoot.node?.children);
|
|
||||||
print(zoomTreeRoot.node?.node?.children);
|
|
||||||
print(zoomTreeRoot.node?.node?.node?.children);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return _isLoaded
|
|
||||||
? Column(children: [
|
|
||||||
Expanded(
|
|
||||||
child: ListView.builder(
|
|
||||||
itemCount: widget.thread.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final isExpanded = _expandedEmails
|
|
||||||
.contains(index); //check if email is expanded
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
ListTile(
|
|
||||||
title: Text(emailsInThread[index].from),
|
|
||||||
trailing: Text(emailsInThread[index].date),
|
|
||||||
onTap: () {
|
|
||||||
setState(() {
|
|
||||||
if (isExpanded) {
|
|
||||||
_expandedEmails.remove(index);
|
|
||||||
} else {
|
|
||||||
_expandedEmails.add(index);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
if (isExpanded)
|
|
||||||
SizedBox(
|
|
||||||
height: heightOfViewTypes[index].toDouble(),
|
|
||||||
child: HtmlElementView(
|
|
||||||
key: UniqueKey(), viewType: viewtypeIDs[index]),
|
|
||||||
),
|
|
||||||
Divider(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
])
|
|
||||||
: const Center(child: CircularProgressIndicator());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
// import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
// import 'package:flutter_html/flutter_html.dart';
|
import 'package:flutter_html/flutter_html.dart';
|
||||||
|
|
||||||
class ContactsPage extends StatefulWidget {
|
class ContactsPage extends StatefulWidget {
|
||||||
const ContactsPage({super.key});
|
const ContactsPage({super.key});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
import 'api_service.dart';
|
import 'api_service.dart';
|
||||||
import 'structs.dart';
|
import 'structs.dart';
|
||||||
import 'emailView.dart';
|
|
||||||
|
|
||||||
class EmailListScreen extends StatelessWidget {
|
class EmailListScreen extends StatelessWidget {
|
||||||
final List<GetThreadResponse> emails;
|
final List<GetThreadResponse> emails;
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
export 'emailViewStub.dart'
|
|
||||||
if (dart.library.io) 'emailViewAndroid.dart'
|
|
||||||
if (dart.library.js_interop) 'emailViewWeb.dart';
|
|
@ -1,95 +0,0 @@
|
|||||||
import 'package:crab_ui/collapsableEmailsAndroid.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
// import 'dart:ui_web' as ui;
|
|
||||||
// import 'augment.dart';
|
|
||||||
// // import 'dart:js_interop' as js; //eventually for manipulating css
|
|
||||||
// import 'package:pointer_interceptor/pointer_interceptor.dart';
|
|
||||||
// import 'collapsableEmails.dart';
|
|
||||||
// import 'api_service.dart';
|
|
||||||
|
|
||||||
class EmailView extends StatefulWidget {
|
|
||||||
final List<String> emailContent;
|
|
||||||
final String from;
|
|
||||||
final String name;
|
|
||||||
final String to;
|
|
||||||
final String subject;
|
|
||||||
final String date;
|
|
||||||
final String id;
|
|
||||||
final List<String> messages;
|
|
||||||
|
|
||||||
const EmailView({
|
|
||||||
Key? key,
|
|
||||||
required this.emailContent,
|
|
||||||
required this.from,
|
|
||||||
required this.name, // tf is name
|
|
||||||
required this.to,
|
|
||||||
required this.subject,
|
|
||||||
required this.date,
|
|
||||||
required this.id,
|
|
||||||
required this.messages,
|
|
||||||
}) : super(key: key);
|
|
||||||
@override
|
|
||||||
_EmailViewState createState() => _EmailViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _EmailViewState extends State<EmailView> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(widget.name),
|
|
||||||
),
|
|
||||||
body: Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
widget.subject,
|
|
||||||
style: TextStyle(fontSize: 15),
|
|
||||||
overflow: TextOverflow.visible,
|
|
||||||
softWrap: true,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'from ${widget.name}',
|
|
||||||
style: TextStyle(fontSize: 8),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'<${widget.from}>',
|
|
||||||
style: TextStyle(fontSize: 8),
|
|
||||||
),
|
|
||||||
Spacer(),
|
|
||||||
Text(
|
|
||||||
widget.date,
|
|
||||||
textAlign: TextAlign.right,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'to ${widget.to.toString()}',
|
|
||||||
style: TextStyle(fontSize: 8),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: CollapsableEmails(
|
|
||||||
thread: widget.messages,
|
|
||||||
threadHTML: widget.emailContent,
|
|
||||||
threadIDs: widget.id,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class EmailView extends StatefulWidget {
|
|
||||||
final List<String> emailContent;
|
|
||||||
final String from;
|
|
||||||
final String name;
|
|
||||||
final String to;
|
|
||||||
final String subject;
|
|
||||||
final String date;
|
|
||||||
final String id;
|
|
||||||
final List<String> messages;
|
|
||||||
|
|
||||||
const EmailView({
|
|
||||||
Key? key,
|
|
||||||
required this.emailContent,
|
|
||||||
required this.from,
|
|
||||||
required this.name,
|
|
||||||
required this.to,
|
|
||||||
required this.subject,
|
|
||||||
required this.date,
|
|
||||||
required this.id,
|
|
||||||
required this.messages,
|
|
||||||
}) : super(key: key);
|
|
||||||
@override
|
|
||||||
_EmailViewState createState() => _EmailViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _EmailViewState extends State<EmailView> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body: Center(
|
|
||||||
child: Text(" emailview stub, not supported")
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,241 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'dart:ui_web' as ui;
|
|
||||||
import 'augment.dart';
|
|
||||||
// import 'dart:js_interop' as js; //eventually for manipulating css
|
|
||||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
|
||||||
import 'collapsableEmails.dart';
|
|
||||||
import 'api_service.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class EmailView extends StatefulWidget {
|
|
||||||
final List<String> emailContent;
|
|
||||||
final String from;
|
|
||||||
final String name;
|
|
||||||
final String to;
|
|
||||||
final String subject;
|
|
||||||
final String date;
|
|
||||||
final String id;
|
|
||||||
final List<String> messages;
|
|
||||||
|
|
||||||
const EmailView({
|
|
||||||
Key? key,
|
|
||||||
required this.emailContent,
|
|
||||||
required this.from,
|
|
||||||
required this.name,
|
|
||||||
required this.to,
|
|
||||||
required this.subject,
|
|
||||||
required this.date,
|
|
||||||
required this.id,
|
|
||||||
required this.messages,
|
|
||||||
}) : super(key: key);
|
|
||||||
@override
|
|
||||||
_EmailViewState createState() => _EmailViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _EmailViewState extends State<EmailView> {
|
|
||||||
//html css rendering thing
|
|
||||||
late Key iframeKey;
|
|
||||||
late String currentContent;
|
|
||||||
late String viewTypeId; //make this a list too???
|
|
||||||
Future<List<Map<String, dynamic>>>? _markerPositionsFuture;
|
|
||||||
// TextEditingController _jumpController = TextEditingController();
|
|
||||||
final hardcodedMarkers = [
|
|
||||||
{'id': 'marker1', 'x': 50, 'y': 100},
|
|
||||||
{'id': 'marker2', 'x': 150, 'y': 200},
|
|
||||||
{'id': 'marker3', 'x': 250, 'y': 300},
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
print("thread id? ${widget.id}");
|
|
||||||
List<String> currentContent = widget
|
|
||||||
.emailContent; //html of the email/ actually entire thread, gives me little space to play in between
|
|
||||||
// i wonder if the other attributes change? because if so i have to add like some zooms in and out of the emails, as in collapse
|
|
||||||
// _registerViewFactory(currentContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// void _registerViewFactory(List<String> currentContent) { // i think this doesnt work anymore
|
|
||||||
// setState(() { //update to do item per item
|
|
||||||
// // each item to have itsviewtype ID
|
|
||||||
// // is this necessarey here??
|
|
||||||
|
|
||||||
// //could just move to collapsable
|
|
||||||
|
|
||||||
// viewTypeId = 'iframe-${DateTime.now().millisecondsSinceEpoch}';
|
|
||||||
// final emailHTML = web.document.createElement('div') as web.HTMLDivElement
|
|
||||||
// ..id = viewTypeId
|
|
||||||
// ..innerHTML = currentContent[0].toJS; // temporarily index because it has to do all of them
|
|
||||||
// emailHTML.style
|
|
||||||
// ..width = '100%'
|
|
||||||
// ..height = '100%'
|
|
||||||
// ..overflow = 'auto'
|
|
||||||
// ..scrollBehavior = 'smooth';
|
|
||||||
|
|
||||||
// ui.platformViewRegistry.registerViewFactory(
|
|
||||||
// viewTypeId,
|
|
||||||
// (int viewId) => emailHTML,
|
|
||||||
// );
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
void _scrollToNumber(String spanId) {
|
|
||||||
AugmentClasses.handleJump(spanId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: void _invisibility(String ) //to make purple numbers not visible
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
// print("thread id ${widget.id}");
|
|
||||||
ApiService.currThreadID = widget.id;
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(widget.name),
|
|
||||||
),
|
|
||||||
body: Stack(
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
EmailToolbar(
|
|
||||||
onJumpToSpan: _scrollToNumber,
|
|
||||||
onButtonPressed: () => {},
|
|
||||||
// AugmentClasses.handleJump(viewTypeId, '1');
|
|
||||||
// print("button got pressed?");
|
|
||||||
|
|
||||||
// _registerViewFactory(r"""
|
|
||||||
// <h1>Welcome to My Website</h1>
|
|
||||||
// <p>This is a simple HTML page.</p>
|
|
||||||
// <h2>What is HTML?</h2>
|
|
||||||
// <p>HTML (HyperText Markup Language) is the most basic building~ block of the Web. It defines the meaning and structure of web content. Other technologies besides HTML are generally used to describe a web page's appearance/presentation (CSS) or functionality/behavior (JavaScript).</p>
|
|
||||||
// <h3>Here's a simple list:</h3>
|
|
||||||
// <ul>
|
|
||||||
// <li>HTML elements are the building blocks of HTML pages</li>
|
|
||||||
// <li>HTML uses tags like <code><tag></code> to organize and format content</li>
|
|
||||||
// <li>CSS is used with HTML to style pages</li>
|
|
||||||
// </ul>
|
|
||||||
// <p>Copyright © 2023</p>
|
|
||||||
// """);
|
|
||||||
// print("change");
|
|
||||||
// widget.emailContent = r"
|
|
||||||
|
|
||||||
//
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
// title of email
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
widget.subject,
|
|
||||||
style: TextStyle(fontSize: 30),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'from ${widget.name}',
|
|
||||||
style: TextStyle(fontSize: 18),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'<${widget.from}>',
|
|
||||||
style: TextStyle(fontSize: 18),
|
|
||||||
),
|
|
||||||
Spacer(),
|
|
||||||
Text(
|
|
||||||
'${widget.date}',
|
|
||||||
textAlign: TextAlign.right,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
// TODO: make a case where if one of these is the user's email it just says me :)))))
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'to ${widget.to.toString()}',
|
|
||||||
style: TextStyle(fontSize: 15),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: CollapsableEmails(
|
|
||||||
//change here
|
|
||||||
thread: widget.messages, //this wont work in serializable
|
|
||||||
threadHTML: widget.emailContent,
|
|
||||||
threadIDs: widget.id,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Expanded(
|
|
||||||
// child: HtmlElementView(
|
|
||||||
// key: UniqueKey(),
|
|
||||||
// viewType: viewTypeId,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
// Overlay widgets dynamically based on marker positions
|
|
||||||
// FutureBuilder<List<Map<String, dynamic>>>(
|
|
||||||
// future: _markerPositionsFuture,
|
|
||||||
// builder: (context, snapshot) {
|
|
||||||
// print("FutureBuilder state: ${snapshot.connectionState}");
|
|
||||||
// if (snapshot.connectionState == ConnectionState.waiting) {
|
|
||||||
// return Center(child: CircularProgressIndicator());
|
|
||||||
// }
|
|
||||||
// if (snapshot.hasError) {
|
|
||||||
// print("Error in FutureBuilder: ${snapshot.error}");
|
|
||||||
// return Center(child: Text('error loading markers'));
|
|
||||||
// }
|
|
||||||
// if (snapshot.hasData && snapshot.data != null) {
|
|
||||||
// final markers = snapshot.data!;
|
|
||||||
// return Stack(
|
|
||||||
// children: markers.map((marker) {
|
|
||||||
// return Positioned(
|
|
||||||
// left: marker['x'].toDouble(),
|
|
||||||
// top: marker['y'].toDouble(),
|
|
||||||
// child: GestureDetector(
|
|
||||||
// onTap: () {
|
|
||||||
// print('Tapped on ${marker['id']}');
|
|
||||||
// },
|
|
||||||
// child: Container(
|
|
||||||
// width: 50,
|
|
||||||
// height: 50,
|
|
||||||
// color: Colors.red,
|
|
||||||
// child: Center(
|
|
||||||
// child: Text(
|
|
||||||
// marker['id'],
|
|
||||||
// style: TextStyle(color: Colors.white),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// }).toList(),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return SizedBox.shrink(); // No markers found
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// Red widget overlay
|
|
||||||
// Positioned(
|
|
||||||
// left: 8, // Adjust based on your desired position
|
|
||||||
// top: 100 + 44 + 5, // Adjust based on your desired position
|
|
||||||
// child: IgnorePointer(
|
|
||||||
// ignoring: true, // Ensures the iframe remains interactive
|
|
||||||
// child: Container(
|
|
||||||
// color: Colors.red,
|
|
||||||
// width: 100,
|
|
||||||
// height: 50,
|
|
||||||
// child: Center(
|
|
||||||
// child: Text(
|
|
||||||
// 'Overlay',
|
|
||||||
// style: TextStyle(color: Colors.white),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
],
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,7 @@ import 'package:crab_ui/sonicEmailView.dart';
|
|||||||
|
|
||||||
import 'folder_drawer.dart';
|
import 'folder_drawer.dart';
|
||||||
import 'structs.dart';
|
import 'structs.dart';
|
||||||
// import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'api_service.dart';
|
import 'api_service.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'email.dart';
|
import 'email.dart';
|
||||||
@ -266,45 +266,40 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Flexible(
|
Container(
|
||||||
child: ConstrainedBox(
|
width: 800,
|
||||||
constraints: BoxConstraints(
|
height: 40,
|
||||||
maxWidth: 800,
|
child: TextField(
|
||||||
),
|
decoration: InputDecoration(
|
||||||
child: SizedBox(
|
hintText: 'Search...',
|
||||||
height: 40,
|
border: OutlineInputBorder(),
|
||||||
child: TextField(
|
prefixIcon: Icon(Icons.search),
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Search...',
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
prefixIcon: Icon(Icons.search),
|
|
||||||
),
|
|
||||||
onSubmitted: (value) {
|
|
||||||
if (value.isNotEmpty) {
|
|
||||||
_performSearch(value, _selectedOption);
|
|
||||||
}
|
|
||||||
//this is the input box i mentioned
|
|
||||||
// if (value == '') {
|
|
||||||
// setState(() {
|
|
||||||
// querySearches = false;
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// Future<List<String>> results = apiService
|
|
||||||
// .sonicSearch('INBOX', 20, 0, value);
|
|
||||||
// // print(value);
|
|
||||||
// print(results);
|
|
||||||
// setState(() {
|
|
||||||
// querySearches = true;
|
|
||||||
// });
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
onSubmitted: (value) {
|
||||||
|
if (value.isNotEmpty) {
|
||||||
|
_performSearch(value, _selectedOption);
|
||||||
|
}
|
||||||
|
//this is the input box i mentioned
|
||||||
|
// if (value == '') {
|
||||||
|
// setState(() {
|
||||||
|
// querySearches = false;
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// Future<List<String>> results = apiService
|
||||||
|
// .sonicSearch('INBOX', 20, 0, value);
|
||||||
|
// // print(value);
|
||||||
|
// print(results);
|
||||||
|
// setState(() {
|
||||||
|
// querySearches = true;
|
||||||
|
// });
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 8,
|
width: 16,
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
|
width: 80,
|
||||||
height: 40,
|
height: 40,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: _showOptionsSearchDialog,
|
onPressed: _showOptionsSearchDialog,
|
||||||
|
@ -1,3 +1,145 @@
|
|||||||
export 'SonicEmailViewStub.dart'
|
import 'package:crab_ui/augment.dart';
|
||||||
if (dart.library.js_interop) 'SonicEmailViewWeb.dart'
|
import 'package:web/web.dart' as web;
|
||||||
if (dart.library.io) 'SonicEmailViewAndroid.dart';
|
import 'dart:ui_web' as ui;
|
||||||
|
import 'dart:js_interop';
|
||||||
|
import 'structs.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class SonicEmailView extends StatefulWidget {
|
||||||
|
SerializableMessage email;
|
||||||
|
String emailHTML;
|
||||||
|
|
||||||
|
SonicEmailView({required this.email, required this.emailHTML});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_SonicEmailViewState createState() => _SonicEmailViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SonicEmailViewState extends State<SonicEmailView> {
|
||||||
|
String viewTypeIDs = "";
|
||||||
|
int heightOFViewtype = 0;
|
||||||
|
bool _isLoaded = false;
|
||||||
|
|
||||||
|
void _scrollToNumber(String spanId) {
|
||||||
|
AugmentClasses.handleJump(spanId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _init() async {
|
||||||
|
await _registerViewFactory(widget.emailHTML);
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() {
|
||||||
|
_isLoaded = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _registerViewFactory(String currentContent) async {
|
||||||
|
// setState(() { //update to do item per item
|
||||||
|
// each item to have itsviewtype ID
|
||||||
|
// is this necessarey here??
|
||||||
|
|
||||||
|
//could just move to collapsable
|
||||||
|
|
||||||
|
// for (var emailHTML in widget.threadHTML) {
|
||||||
|
String viewTypeId = 'email-${DateTime.now().millisecondsSinceEpoch}';
|
||||||
|
|
||||||
|
final ghost = web.document.createElement('div') as web.HTMLDivElement
|
||||||
|
..style.visibility = 'hidden'
|
||||||
|
..style.position = 'absolute'
|
||||||
|
..style.width = '100%'
|
||||||
|
..style.overflow = 'auto'
|
||||||
|
..innerHTML = currentContent.toJS;
|
||||||
|
web.document.body?.append(ghost);
|
||||||
|
await Future.delayed(Duration(milliseconds: 10));
|
||||||
|
|
||||||
|
final heightOfEmail = ghost.scrollHeight;
|
||||||
|
ghost.remove();
|
||||||
|
|
||||||
|
final HTMLsnippet = web.document.createElement('div') as web.HTMLDivElement
|
||||||
|
..id = viewTypeId
|
||||||
|
..innerHTML = widget
|
||||||
|
.emailHTML.toJS; // temporarily index because it has to do all of them
|
||||||
|
HTMLsnippet.style
|
||||||
|
..width = '100%'
|
||||||
|
..height = '${heightOfEmail}px'
|
||||||
|
..overflow = 'auto'
|
||||||
|
..scrollBehavior = 'smooth';
|
||||||
|
|
||||||
|
ui.platformViewRegistry.registerViewFactory(
|
||||||
|
viewTypeId,
|
||||||
|
(int viewId) => HTMLsnippet,
|
||||||
|
);
|
||||||
|
this.viewTypeIDs = viewTypeId;
|
||||||
|
this.heightOFViewtype = heightOfEmail;
|
||||||
|
print(viewTypeIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return _isLoaded
|
||||||
|
? Scaffold(
|
||||||
|
appBar: AppBar(title: Text(widget.email.subject)),
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
EmailToolbar(
|
||||||
|
onButtonPressed: () => {},
|
||||||
|
onJumpToSpan: _scrollToNumber),
|
||||||
|
Row(
|
||||||
|
// title of email
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
widget.email.subject,
|
||||||
|
style: TextStyle(fontSize: 30),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'from ${widget.email.name}',
|
||||||
|
style: TextStyle(fontSize: 18),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'<${widget.email.from}>',
|
||||||
|
style: TextStyle(fontSize: 18),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
Text(
|
||||||
|
'${widget.email.date}',
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// TODO: make a case where if one of these is the user's email it just says me :)))))
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'to ${widget.email.to.toString()}',
|
||||||
|
style: TextStyle(fontSize: 15),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
// child: SizedBox(
|
||||||
|
// height: heightOFViewtype.toDouble(),
|
||||||
|
child: HtmlElementView(
|
||||||
|
key: UniqueKey(), viewType: this.viewTypeIDs,
|
||||||
|
// ),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -127,8 +127,7 @@ class AttachmentInfoList extends Iterable<AttachmentInfo> {
|
|||||||
AttachmentInfoList(this._attachments);
|
AttachmentInfoList(this._attachments);
|
||||||
|
|
||||||
factory AttachmentInfoList.fromJsonList(List<Map<String, dynamic>> jsonList) {
|
factory AttachmentInfoList.fromJsonList(List<Map<String, dynamic>> jsonList) {
|
||||||
return AttachmentInfoList(
|
return AttachmentInfoList(jsonList.map((json) => AttachmentInfo.fromJson(json)).toList());
|
||||||
jsonList.map((json) => AttachmentInfo.fromJson(json)).toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -144,13 +143,6 @@ class AttachmentResponse {
|
|||||||
AttachmentResponse({required this.name, required this.data});
|
AttachmentResponse({required this.name, required this.data});
|
||||||
|
|
||||||
factory AttachmentResponse.fromJson(Map<String, dynamic> json) {
|
factory AttachmentResponse.fromJson(Map<String, dynamic> json) {
|
||||||
return AttachmentResponse(
|
return AttachmentResponse(name: json["name"], data: Uint8List.fromList(List<int>.from(json["data"])));
|
||||||
name: json["name"],
|
|
||||||
data: Uint8List.fromList(List<int>.from(json["data"])));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AugmentTree {
|
|
||||||
List children = [];
|
|
||||||
AugmentTree? node;
|
|
||||||
}
|
|
||||||
|
522
pubspec.lock
@ -12,12 +12,14 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
http: 1.2.2
|
http: 1.2.2
|
||||||
|
flutter_html_all: 3.0.0-beta.2
|
||||||
|
flutter_widget_from_html: ^0.10.0
|
||||||
shared_preferences: ^2.0.6
|
shared_preferences: ^2.0.6
|
||||||
encrypt: ^5.0.0
|
encrypt: ^5.0.0
|
||||||
pointycastle: ^3.4.0
|
pointycastle: ^3.4.0
|
||||||
mime: ^1.0.3
|
mime: ^1.0.3
|
||||||
pointer_interceptor: ^0.10.1+2
|
pointer_interceptor: ^0.10.1+2
|
||||||
|
file_saver: ^0.2.14
|
||||||
|
|
||||||
|
|
||||||
english_words: ^4.0.0
|
english_words: ^4.0.0
|
||||||
@ -26,7 +28,6 @@ dependencies:
|
|||||||
pdfrx: ^1.0.94
|
pdfrx: ^1.0.94
|
||||||
photo_view: ^0.15.0
|
photo_view: ^0.15.0
|
||||||
web: ^1.1.1
|
web: ^1.1.1
|
||||||
flutter_widget_from_html: ^0.16.0
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@ -38,7 +39,6 @@ dependency_overrides:
|
|||||||
flutter_layout_grid: 2.0.7
|
flutter_layout_grid: 2.0.7
|
||||||
flutter_math_fork: 0.7.2
|
flutter_math_fork: 0.7.2
|
||||||
|
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
assets:
|
assets:
|
||||||
|