fix(uiux): Major reimplementation of tiles, refactoring and tightening of UI (#525)
* fix(database): Use native extension instead of describeEnum * new(sonarr): [Catalogue] Previous airing sorting options * splash: Rebuild Android & iOS splash screens * changelog: Refactor changelog sheet * Continued WIP Polish of UI * chore: Reintegrate pods * calendar: Added second line for Lidarr/Radarr entries * settings: Show quick actions information as banner block * lidarr: Add support for monitoring options on add, posters in result list * uiux: Fade edges of scrollable text * drawer: Restyle header * Remove redundant body texts in edit/add content * macos: Set window size & alignment * settings: Add description banner block for profiles
@@ -1,6 +1,5 @@
|
||||
android/app/google-services.json
|
||||
android/key.jks
|
||||
android/key.properties
|
||||
ios/ExportOptions.plist
|
||||
ios/GoogleService-Info.plist
|
||||
macos/GoogleService-Info.plist
|
||||
|
||||
1
.gitignore
vendored
@@ -52,7 +52,6 @@ coverage/
|
||||
/android/key.properties
|
||||
/android/app/google-services.json
|
||||
/android/key.jks
|
||||
/ios/ExportOptions.plist
|
||||
/ios/GoogleService-Info.plist
|
||||
/macos/GoogleService-Info.plist
|
||||
/vendor/font_awesome_flutter/lib/fonts/fa-thin-100.ttf
|
||||
|
||||
30
CHANGELOG.md
@@ -1,17 +1,41 @@
|
||||
# LunaSea Changelog
|
||||
|
||||
## WIP
|
||||
## v6.0.0 (60000004)
|
||||
|
||||
#### NEW
|
||||
|
||||
- `[Settings]` (Configuration) Show dismissable banner with module information and links
|
||||
- `[Dashboard]` (Calendar) Display content poster and additional information
|
||||
- `[Firebase]` (Analytics) Completely removed Analytics and Crashlytics
|
||||
- `[Settings]` Show dismissable blocks with information and links
|
||||
- `[Lidarr]` (Add Artist) Show artist poster in result list
|
||||
- `[Lidarr]` (Add Artist) Allow user to select monitoring options
|
||||
- `[Lidarr]` (Add Artist) Removed toggle to use album folders
|
||||
- `[Lidarr]` (Catalogue) Show artist poster in catalogue list
|
||||
- `[Lidarr]` (Missing) Display album covers
|
||||
- `[Sonarr]` (Catalogue) Previous airing sorting option
|
||||
- `[Sonarr]` (Season List) Display season posters
|
||||
- `[Sonarr]` (Queue) Option to set queue page size
|
||||
- `[UI/UX]` (Tile Blocks) Allow overflowing title or body lines to be horizontally scrolled
|
||||
|
||||
#### TWEAKS
|
||||
|
||||
- `[UI/UX]` (Drawer) Heavily reduced the size of the header area
|
||||
- `[UI/UX]` (Fonts) Normalized font sizes across the UI
|
||||
- `[UI/UX]` (Images) Set the default image opacity to 20% (custom set values are uneffected)
|
||||
- `[UI/UX]` (Tile Blocks) Heavily improved build and memory performance of tiles
|
||||
- `[UI/UX]` (Tile Blocks) Improved consistency in trailing icon/text size
|
||||
- `[UI/UX]` (Tile Blocks) Improved consistency of tile height, content spacing, and padding
|
||||
- `[UI/UX]` (Tile Blocks) Natively draw placeholder posters for movies, series, albums, etc.
|
||||
- `[UI/UX]` (Tile Blocks) Fade-in background image loads
|
||||
- `[UI/UX]` (Tooltips) Added styling to match LunaSea theme
|
||||
|
||||
#### FIXES
|
||||
|
||||
- `[Dashboard]` (Calendar) Lidarr entries would not appear
|
||||
- `[Dashboard]` (Modules) Unbranded icons could use incorrect colours
|
||||
- `[UI/UX]` (List Tiles) Fixed consistency of trailing icon/text size
|
||||
- `[Lidarr]` (Albums) List would fail to load on nightly Lidarr builds
|
||||
- `[Sonarr]` (Catalogue) Missing filter would fail to load when using Sonarr v4 in some cases
|
||||
- `[Sonarr]` (Images) Images now use v3 API path
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -22,9 +22,8 @@ if (flutterVersionName == null) {
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
def keystoreProperties = new Properties()
|
||||
@@ -34,20 +33,25 @@ if (keystorePropertiesFile.exists()) {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
compileSdkVersion 31
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'InvalidPackage'
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "app.lunasea.lunasea"
|
||||
minSdkVersion 24
|
||||
targetSdkVersion 30
|
||||
targetSdkVersion 31
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="app.lunasea.lunasea">
|
||||
<application
|
||||
android:name="io.flutter.app.FlutterApplication"
|
||||
android:name="${applicationName}"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:label="LunaSea"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
@@ -17,6 +17,7 @@
|
||||
android:value="true" />
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
|
||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 5.2 KiB |
BIN
android/app/src/main/res/drawable-v21/background.png
Normal file
|
After Width: | Height: | Size: 70 B |
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
</layer-list>
|
||||
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 30 KiB |
BIN
android/app/src/main/res/drawable/background.png
Normal file
|
After Width: | Height: | Size: 70 B |
@@ -1,16 +1,9 @@
|
||||
<?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="@color/splash_color" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash" />
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
|
||||
</layer-list>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
</layer-list>
|
||||
17
android/app/src/main/res/values-v31/styles.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?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.Black.NoTitleBar">
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowSplashScreenBackground">#32323E</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>
|
||||
@@ -5,6 +5,7 @@
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
Flutter draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:windowFullscreen">false</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
|
||||
@@ -15,6 +16,5 @@
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">@color/splash_color</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,22 +1,21 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.50'
|
||||
ext.kotlin_version = '1.5.32'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.6.4'
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath 'com.google.gms:google-services:4.3.3'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.2.0'
|
||||
classpath 'com.google.gms:google-services:4.3.8'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.enableR8=true
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
|
||||
|
||||
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 28 KiB |
@@ -6,11 +6,13 @@
|
||||
"settings.AccountHelp": "LunaSea Account",
|
||||
"settings.AccountHelpHint1": "LunaSea offers a free account to backup your configuration to the cloud, with additional features coming in the future!",
|
||||
"settings.AccountSettings": "Account Settings",
|
||||
"settings.Add": "Add",
|
||||
"settings.AddHeader": "Add Header",
|
||||
"settings.AddModule": "Add Module",
|
||||
"settings.AddModuleFailed": "Failed to Add Module",
|
||||
"settings.AddModuleSuccess": "Module Added",
|
||||
"settings.AddProfile": "Add Profile",
|
||||
"settings.AddProfileDescription": "Add a New Profile",
|
||||
"settings.AllFieldsAreRequired": "All fields are required",
|
||||
"settings.AmoledTheme": "AMOLED Theme",
|
||||
"settings.AmoledThemeBorders": "AMOLED Theme Borders",
|
||||
@@ -62,6 +64,10 @@
|
||||
"settings.CustomHeaders": "Custom Headers",
|
||||
"settings.CustomHeadersDescription": "Add Custom Headers to Requests",
|
||||
"settings.DefaultPage": "Default Page",
|
||||
"settings.DefaultPages": "Default Pages",
|
||||
"settings.DefaultPagesDescription": "Set Default Landing Pages",
|
||||
"settings.DefaultSortingAndFiltering": "Default Sorting & Filtering",
|
||||
"settings.DefaultSortingAndFilteringDescription": "Set Default Sorting & Filtering Methods",
|
||||
"settings.DecryptBackup": "Decrypt Backup",
|
||||
"settings.DecryptBackupHint1": "Please enter the encryption key for this backup.",
|
||||
"settings.DebugMenu": "Debug Menu",
|
||||
@@ -83,6 +89,7 @@
|
||||
"settings.DeleteModuleHint1": "Are you sure you want to delete this external module?",
|
||||
"settings.DeleteModuleSuccess": "Module Deleted",
|
||||
"settings.DeleteProfile": "Delete Profile",
|
||||
"settings.DeleteProfileDescription": "Delete an Existing Profile",
|
||||
"settings.DismissBanners": "Dismiss Banners",
|
||||
"settings.DismissBannersHint1": "Are you sure you want to dismiss all tooltip banners?",
|
||||
"settings.DismissBannersHint2": "The tooltip banners will give you tips and hints for features available within LunaSea.",
|
||||
@@ -158,6 +165,7 @@
|
||||
"settings.RegisteredFailure": "Failed to Register",
|
||||
"settings.RegisteredSuccess": "Successfully Registered",
|
||||
"settings.RenameProfile": "Rename Profile",
|
||||
"settings.RenameProfileDescription": "Rename an Existing Profile",
|
||||
"settings.ResetPassword": "Reset Password",
|
||||
"settings.Resources": "Resources",
|
||||
"settings.ResourcesDescription": "Useful Resources & Links",
|
||||
@@ -185,6 +193,7 @@
|
||||
"settings.Username": "Username",
|
||||
"settings.UsernameValidation": "Username Required",
|
||||
"settings.MustBeValueBetween": "Must be a value between {} and {}",
|
||||
"lunasea.Ascending": "Ascending",
|
||||
"lunasea.Add": "Add",
|
||||
"lunasea.AnErrorHasOccurred": "An Error Has Occurred",
|
||||
"lunasea.BackUp": "Back Up",
|
||||
@@ -196,12 +205,14 @@
|
||||
"lunasea.ComingSoon": "Coming Soon",
|
||||
"lunasea.Dashboard": "Dashboard",
|
||||
"lunasea.Delete": "Delete",
|
||||
"lunasea.Descending": "Descending",
|
||||
"lunasea.Disable": "Disable",
|
||||
"lunasea.Disabled": "Disabled",
|
||||
"lunasea.Dismiss": "Dismiss",
|
||||
"lunasea.ExternalModules": "External Modules",
|
||||
"lunasea.GoBack": "Go Back",
|
||||
"lunasea.GoToSettings": "Go to Settings",
|
||||
"lunasea.Home": "Home",
|
||||
"lunasea.IncorrectEncryptionKey": "Incorrect encryption key",
|
||||
"lunasea.Module": "Module",
|
||||
"lunasea.ModuleIsNotEnabled": "{} Is Not Enabled",
|
||||
@@ -267,6 +278,7 @@
|
||||
"radarr.ManualImportDescription": "Import Movies from the Filesystem",
|
||||
"radarr.MinimumAvailability": "Minimum Availability",
|
||||
"radarr.Missing": "Missing",
|
||||
"radarr.Monitor": "Monitor",
|
||||
"radarr.Monitored": "Monitored",
|
||||
"radarr.MonitoredDescription": "Monitor for new releases",
|
||||
"radarr.MonitorMovie": "Monitor Movie",
|
||||
@@ -311,6 +323,8 @@
|
||||
"radarr.SelectQuality": "Select Quality",
|
||||
"radarr.Size": "Size",
|
||||
"radarr.SortCatalogue": "Sort Catalogue",
|
||||
"radarr.StartSearchFor": "Start Search For…",
|
||||
"radarr.StartSearchForMissingMovie": "Start search for missing movie",
|
||||
"radarr.Studio": "Studio",
|
||||
"radarr.SystemStatus": "System Status",
|
||||
"radarr.SystemStatusDescription": "System Status & Disk Space",
|
||||
@@ -549,7 +563,7 @@
|
||||
"sonarr.MonitorSeries": "Monitor Series",
|
||||
"sonarr.Monitored": "Monitored",
|
||||
"sonarr.Monitoring": "Monitoring",
|
||||
"sonarr.MonitoredDescription": "Monitor series for new releases",
|
||||
"sonarr.MonitoredDescription": "Download monitored episodes in this series",
|
||||
"sonarr.More": "More",
|
||||
"sonarr.Name": "Name",
|
||||
"sonarr.NoEpisodesFound": "No Episodes Found",
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>compileBitcode</key>
|
||||
<true/>
|
||||
<key>method</key>
|
||||
<string>development</string>
|
||||
<key>signingStyle</key>
|
||||
<string>automatic</string>
|
||||
<key>stripSwiftSymbols</key>
|
||||
<true/>
|
||||
<!--
|
||||
WHAT YOU SHOULD EDIT BELOW
|
||||
-->
|
||||
<key>teamID</key>
|
||||
<string>INSERT-YOUR-TEAMID-HERE</string>
|
||||
<!--
|
||||
WHAT YOU SHOULD EDIT ABOVE
|
||||
-->
|
||||
<key>thinning</key>
|
||||
<string><none></string>
|
||||
</dict>
|
||||
</plist>
|
||||
139
ios/Podfile.lock
@@ -1,5 +1,5 @@
|
||||
PODS:
|
||||
- cloud_firestore (3.1.0):
|
||||
- cloud_firestore (3.1.5):
|
||||
- Firebase/Firestore (= 8.9.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
@@ -37,19 +37,11 @@ PODS:
|
||||
- file_picker (0.0.1):
|
||||
- DKImagePickerController/PhotoGallery
|
||||
- Flutter
|
||||
- Firebase/Analytics (8.9.0):
|
||||
- Firebase/Core
|
||||
- Firebase/Auth (8.9.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseAuth (~> 8.9.0)
|
||||
- Firebase/Core (8.9.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseAnalytics (~> 8.9.0)
|
||||
- Firebase/CoreOnly (8.9.0):
|
||||
- FirebaseCore (= 8.9.0)
|
||||
- Firebase/Crashlytics (8.9.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseCrashlytics (~> 8.9.0)
|
||||
- Firebase/Firestore (8.9.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseFirestore (~> 8.9.0)
|
||||
@@ -59,47 +51,21 @@ PODS:
|
||||
- Firebase/Storage (8.9.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseStorage (~> 8.9.0)
|
||||
- firebase_analytics (8.3.4):
|
||||
- Firebase/Analytics (= 8.9.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_auth (3.2.0):
|
||||
- firebase_auth (3.3.4):
|
||||
- Firebase/Auth (= 8.9.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_core (1.10.0):
|
||||
- firebase_core (1.10.6):
|
||||
- Firebase/CoreOnly (= 8.9.0)
|
||||
- Flutter
|
||||
- firebase_crashlytics (2.3.0):
|
||||
- Firebase/Crashlytics (= 8.9.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_messaging (11.1.0):
|
||||
- firebase_messaging (11.2.4):
|
||||
- Firebase/Messaging (= 8.9.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_storage (10.1.0):
|
||||
- firebase_storage (10.2.4):
|
||||
- Firebase/Storage (= 8.9.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- FirebaseAnalytics (8.9.1):
|
||||
- FirebaseAnalytics/AdIdSupport (= 8.9.1)
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (~> 8.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.6)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.6)
|
||||
- GoogleUtilities/Network (~> 7.6)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.6)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- FirebaseAnalytics/AdIdSupport (8.9.1):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (~> 8.0)
|
||||
- GoogleAppMeasurement (= 8.9.1)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.6)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.6)
|
||||
- GoogleUtilities/Network (~> 7.6)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.6)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- FirebaseAuth (8.9.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.6)
|
||||
@@ -109,18 +75,11 @@ PODS:
|
||||
- FirebaseCoreDiagnostics (~> 8.0)
|
||||
- GoogleUtilities/Environment (~> 7.6)
|
||||
- GoogleUtilities/Logger (~> 7.6)
|
||||
- FirebaseCoreDiagnostics (8.9.0):
|
||||
- FirebaseCoreDiagnostics (8.10.0):
|
||||
- GoogleDataTransport (~> 9.1)
|
||||
- GoogleUtilities/Environment (~> 7.6)
|
||||
- GoogleUtilities/Logger (~> 7.6)
|
||||
- nanopb (~> 2.30908.0)
|
||||
- FirebaseCrashlytics (8.9.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (~> 8.0)
|
||||
- GoogleDataTransport (~> 9.1)
|
||||
- GoogleUtilities/Environment (~> 7.6)
|
||||
- nanopb (~> 2.30908.0)
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- FirebaseFirestore (8.9.0):
|
||||
- FirebaseFirestore/AutodetectLeveldb (= 8.9.0)
|
||||
- FirebaseFirestore/AutodetectLeveldb (8.9.0):
|
||||
@@ -129,7 +88,7 @@ PODS:
|
||||
- FirebaseFirestore/Base (8.9.0)
|
||||
- FirebaseFirestore/WithLeveldb (8.9.0):
|
||||
- FirebaseFirestore/Base
|
||||
- FirebaseInstallations (8.9.0):
|
||||
- FirebaseInstallations (8.10.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- GoogleUtilities/Environment (~> 7.6)
|
||||
- GoogleUtilities/UserDefaults (~> 7.6)
|
||||
@@ -147,26 +106,6 @@ PODS:
|
||||
- FirebaseCore (~> 8.0)
|
||||
- GTMSessionFetcher/Core (~> 1.5)
|
||||
- Flutter (1.0.0)
|
||||
- GoogleAppMeasurement (8.9.1):
|
||||
- GoogleAppMeasurement/AdIdSupport (= 8.9.1)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.6)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.6)
|
||||
- GoogleUtilities/Network (~> 7.6)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.6)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- GoogleAppMeasurement/AdIdSupport (8.9.1):
|
||||
- GoogleAppMeasurement/WithoutAdIdSupport (= 8.9.1)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.6)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.6)
|
||||
- GoogleUtilities/Network (~> 7.6)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.6)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- GoogleAppMeasurement/WithoutAdIdSupport (8.9.1):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.6)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.6)
|
||||
- GoogleUtilities/Network (~> 7.6)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.6)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- GoogleDataTransport (9.1.2):
|
||||
- GoogleUtilities/Environment (~> 7.2)
|
||||
- nanopb (~> 2.30908.0)
|
||||
@@ -214,7 +153,7 @@ PODS:
|
||||
- nanopb/encode (2.30908.0)
|
||||
- package_info_plus (0.4.5):
|
||||
- Flutter
|
||||
- path_provider (0.0.1):
|
||||
- path_provider_ios (0.0.1):
|
||||
- Flutter
|
||||
- PromisesObjC (2.0.0)
|
||||
- quick_actions (0.0.1):
|
||||
@@ -224,20 +163,18 @@ PODS:
|
||||
- SDWebImage/Core (5.12.1)
|
||||
- share_plus (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences (0.0.1):
|
||||
- shared_preferences_ios (0.0.1):
|
||||
- Flutter
|
||||
- SwiftyGif (5.4.0)
|
||||
- url_launcher (0.0.1):
|
||||
- SwiftyGif (5.4.2)
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
- Firebase/Messaging
|
||||
- firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`)
|
||||
- firebase_auth (from `.symlinks/plugins/firebase_auth/ios`)
|
||||
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
||||
- firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
|
||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||
- firebase_storage (from `.symlinks/plugins/firebase_storage/ios`)
|
||||
- FirebaseFirestore (from `https://github.com/invertase/firestore-ios-sdk-frameworks.git`, tag `8.9.0`)
|
||||
@@ -245,26 +182,23 @@ DEPENDENCIES:
|
||||
- GoogleUtilities
|
||||
- in_app_purchase_ios (from `.symlinks/plugins/in_app_purchase_ios/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider (from `.symlinks/plugins/path_provider/ios`)
|
||||
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
|
||||
- quick_actions (from `.symlinks/plugins/quick_actions/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
|
||||
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
|
||||
- shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- DKImagePickerController
|
||||
- DKPhotoGallery
|
||||
- Firebase
|
||||
- FirebaseAnalytics
|
||||
- FirebaseAuth
|
||||
- FirebaseCore
|
||||
- FirebaseCoreDiagnostics
|
||||
- FirebaseCrashlytics
|
||||
- FirebaseInstallations
|
||||
- FirebaseMessaging
|
||||
- FirebaseStorage
|
||||
- GoogleAppMeasurement
|
||||
- GoogleDataTransport
|
||||
- GoogleUtilities
|
||||
- GTMSessionFetcher
|
||||
@@ -278,14 +212,10 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/cloud_firestore/ios"
|
||||
file_picker:
|
||||
:path: ".symlinks/plugins/file_picker/ios"
|
||||
firebase_analytics:
|
||||
:path: ".symlinks/plugins/firebase_analytics/ios"
|
||||
firebase_auth:
|
||||
:path: ".symlinks/plugins/firebase_auth/ios"
|
||||
firebase_core:
|
||||
:path: ".symlinks/plugins/firebase_core/ios"
|
||||
firebase_crashlytics:
|
||||
:path: ".symlinks/plugins/firebase_crashlytics/ios"
|
||||
firebase_messaging:
|
||||
:path: ".symlinks/plugins/firebase_messaging/ios"
|
||||
firebase_storage:
|
||||
@@ -299,16 +229,16 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/in_app_purchase_ios/ios"
|
||||
package_info_plus:
|
||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||
path_provider:
|
||||
:path: ".symlinks/plugins/path_provider/ios"
|
||||
path_provider_ios:
|
||||
:path: ".symlinks/plugins/path_provider_ios/ios"
|
||||
quick_actions:
|
||||
:path: ".symlinks/plugins/quick_actions/ios"
|
||||
share_plus:
|
||||
:path: ".symlinks/plugins/share_plus/ios"
|
||||
shared_preferences:
|
||||
:path: ".symlinks/plugins/shared_preferences/ios"
|
||||
url_launcher:
|
||||
:path: ".symlinks/plugins/url_launcher/ios"
|
||||
shared_preferences_ios:
|
||||
:path: ".symlinks/plugins/shared_preferences_ios/ios"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
|
||||
CHECKOUT OPTIONS:
|
||||
FirebaseFirestore:
|
||||
@@ -316,43 +246,38 @@ CHECKOUT OPTIONS:
|
||||
:tag: 8.9.0
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
cloud_firestore: 2cff0618e560f435fc05da5c94c2d213eb7ba640
|
||||
cloud_firestore: 338122a6149c14ca376ad363626b5bf3037a5056
|
||||
DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d
|
||||
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
||||
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
|
||||
Firebase: 13d8d96499e2635428d5bf0ec675df21f95d9a95
|
||||
firebase_analytics: 7a7528bb2abf4ca22cff7a57bbf909dcab73e13d
|
||||
firebase_auth: 0d56cc4d105ff70d1547a7fcb10ee574ad05adf5
|
||||
firebase_core: f770e033e790657b3505f04be4cb24c482912f11
|
||||
firebase_crashlytics: ed8c1d66dc407d617cbed798f05a5d9115da7494
|
||||
firebase_messaging: 0c8d1a1732487db7f332fb65232053e93201e2fb
|
||||
firebase_storage: a3bbe618ef41930ae31da8f4691d37e4ed84f14d
|
||||
FirebaseAnalytics: 4ab446ce08a3fe52e8a4303dd997cf26276bf968
|
||||
firebase_auth: e875a50b81aefb20f305dfede425647e9675c19e
|
||||
firebase_core: c263d7daf1dc92fcd9895e6abdc04872b0ee07ff
|
||||
firebase_messaging: dff5cd08781ee1de988565a83c977e435405cd7e
|
||||
firebase_storage: 2ed331c6bd5bfa6d64f1a6c57f01151f4f146c16
|
||||
FirebaseAuth: 2b78b2a32c07b3ecfa4970bdf1d3632b8304099b
|
||||
FirebaseCore: 599ee609343eaf4941bd188f85e3aa077ffe325b
|
||||
FirebaseCoreDiagnostics: 5daa63f1c1409d981a2d5007daa100b36eac6a34
|
||||
FirebaseCrashlytics: 40efbd81157dae307ec95612fa1328347284d2c2
|
||||
FirebaseCoreDiagnostics: 56fb7216d87e0e6ec2feddefa9d8a392fe8b2c18
|
||||
FirebaseFirestore: 7c22bff6c0e1f222920cd110e9da13a117b61fea
|
||||
FirebaseInstallations: caa7c8e0d3e2345b8829d2fa9ca1b4dfbf2fcc85
|
||||
FirebaseInstallations: 830327b45345ffc859eaa9c17bcd5ae893fd5425
|
||||
FirebaseMessaging: 82c4a48638f53f7b184f3cc9f6cd2cbe533ab316
|
||||
FirebaseStorage: 452c98c31ccb40b819764bf3039426c4388d9939
|
||||
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
|
||||
GoogleAppMeasurement: 837649ad3987936c232f6717c5680216f6243d24
|
||||
GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940
|
||||
GoogleUtilities: 684ee790a24f73ebb2d1d966e9711c203f2a4237
|
||||
GTMSessionFetcher: 43748f93435c2aa068b1cbe39655aaf600652e91
|
||||
in_app_purchase_ios: 04ed55fdd1012db54095d6801335b5f5de0a475f
|
||||
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
|
||||
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
|
||||
path_provider: d1e9807085df1f9cc9318206cd649dc0b76be3de
|
||||
path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5
|
||||
PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58
|
||||
quick_actions: cd83314083fa994182e6cd9e7516167a215a4f83
|
||||
SDWebImage: 4dc3e42d9ec0c1028b960a33ac6b637bb432207b
|
||||
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
|
||||
shared_preferences: 5033afbb22d372e15aff8ff766df9021b845f273
|
||||
SwiftyGif: 5d4af95df24caf1c570dbbcb32a3b8a0763bc6d7
|
||||
url_launcher: b6e016d912f04be9f5bf6e8e82dc599b7ba59649
|
||||
shared_preferences_ios: aef470a42dc4675a1cdd50e3158b42e3d1232b32
|
||||
SwiftyGif: dec758a9dd3d278e5a855dbf279bf062c923c387
|
||||
url_launcher_ios: 02f1989d4e14e998335b02b67a7590fa34f971af
|
||||
|
||||
PODFILE CHECKSUM: 6140814a61b9571bc8e1daa6ec9af34598f6e610
|
||||
|
||||
COCOAPODS: 1.10.2
|
||||
COCOAPODS: 1.11.2
|
||||
|
||||
@@ -3,15 +3,14 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
1EA81D57F09988D75AC476F5 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE878F72B0C2DCB5A4603ABD /* Pods_Runner.framework */; };
|
||||
22ABA27907009C6D67E17F02 /* Pods_ImageNotification.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7DDBAA25D93558DC2ACE8794 /* Pods_ImageNotification.framework */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
7585ADE8DCB47DC8753EF72A /* Pods_ImageNotification.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 989B86C0CD70FC0AB24F07D6 /* Pods_ImageNotification.framework */; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
@@ -19,6 +18,7 @@
|
||||
9C5DBBF2257EB50400836D8D /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9C5DBBF1257EB50400836D8D /* GoogleService-Info.plist */; };
|
||||
9C7092B325E77E470056AE0B /* NotificationService.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C7092B225E77E470056AE0B /* NotificationService.m */; };
|
||||
9C7092B725E77E470056AE0B /* ImageNotification.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 9C7092AF25E77E470056AE0B /* ImageNotification.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
E81187C204448290256D1292 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 525B84ABAED8CC10DD278134 /* Pods_Runner.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -58,14 +58,13 @@
|
||||
/* Begin PBXFileReference section */
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
1F2EFFABEACE166F53F7025F /* Pods-ImageNotification.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageNotification.debug.xcconfig"; path = "Target Support Files/Pods-ImageNotification/Pods-ImageNotification.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
2FC45D8C03585F29FFEEBAD5 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
1AEC3393F733CF63CC471C78 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
50F2C55D9F5DC33EBDADB9C4 /* Pods-ImageNotification.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageNotification.profile.xcconfig"; path = "Target Support Files/Pods-ImageNotification/Pods-ImageNotification.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
525B84ABAED8CC10DD278134 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
76B7822037A027527BE9DFD3 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
7DDBAA25D93558DC2ACE8794 /* Pods_ImageNotification.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ImageNotification.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -73,7 +72,6 @@
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
989B86C0CD70FC0AB24F07D6 /* Pods_ImageNotification.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ImageNotification.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9C0A396F23E0F00900EC8127 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||
9C2991232453FE3100B93AB2 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
|
||||
9C5DBBF1257EB50400836D8D /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||
@@ -83,9 +81,11 @@
|
||||
9C7092B125E77E470056AE0B /* NotificationService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NotificationService.h; sourceTree = "<group>"; };
|
||||
9C7092B225E77E470056AE0B /* NotificationService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NotificationService.m; sourceTree = "<group>"; };
|
||||
9C7092B425E77E470056AE0B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
AE878F72B0C2DCB5A4603ABD /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D94DB394AEFBDD2422D8B950 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
EC88C989B98F6E7BDEBE5FE5 /* Pods-ImageNotification.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageNotification.release.xcconfig"; path = "Target Support Files/Pods-ImageNotification/Pods-ImageNotification.release.xcconfig"; sourceTree = "<group>"; };
|
||||
AB50C11FF4EFC5D9961D1031 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
ACE755908B540FD8855E4D89 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
C041C2ED656F3E1D27D9E228 /* Pods-ImageNotification.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageNotification.debug.xcconfig"; path = "Target Support Files/Pods-ImageNotification/Pods-ImageNotification.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
C9A446482226EB46FF708884 /* Pods-ImageNotification.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageNotification.profile.xcconfig"; path = "Target Support Files/Pods-ImageNotification/Pods-ImageNotification.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
FE066D193740042A640E4E50 /* Pods-ImageNotification.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageNotification.release.xcconfig"; path = "Target Support Files/Pods-ImageNotification/Pods-ImageNotification.release.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -94,7 +94,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9C2991242453FE3100B93AB2 /* StoreKit.framework in Frameworks */,
|
||||
1EA81D57F09988D75AC476F5 /* Pods_Runner.framework in Frameworks */,
|
||||
E81187C204448290256D1292 /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -102,7 +102,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
7585ADE8DCB47DC8753EF72A /* Pods_ImageNotification.framework in Frameworks */,
|
||||
22ABA27907009C6D67E17F02 /* Pods_ImageNotification.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -182,8 +182,8 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9C2991232453FE3100B93AB2 /* StoreKit.framework */,
|
||||
989B86C0CD70FC0AB24F07D6 /* Pods_ImageNotification.framework */,
|
||||
AE878F72B0C2DCB5A4603ABD /* Pods_Runner.framework */,
|
||||
7DDBAA25D93558DC2ACE8794 /* Pods_ImageNotification.framework */,
|
||||
525B84ABAED8CC10DD278134 /* Pods_Runner.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -191,12 +191,12 @@
|
||||
F5D05D221249C73674C5DB0D /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1F2EFFABEACE166F53F7025F /* Pods-ImageNotification.debug.xcconfig */,
|
||||
EC88C989B98F6E7BDEBE5FE5 /* Pods-ImageNotification.release.xcconfig */,
|
||||
50F2C55D9F5DC33EBDADB9C4 /* Pods-ImageNotification.profile.xcconfig */,
|
||||
2FC45D8C03585F29FFEEBAD5 /* Pods-Runner.debug.xcconfig */,
|
||||
76B7822037A027527BE9DFD3 /* Pods-Runner.release.xcconfig */,
|
||||
D94DB394AEFBDD2422D8B950 /* Pods-Runner.profile.xcconfig */,
|
||||
C041C2ED656F3E1D27D9E228 /* Pods-ImageNotification.debug.xcconfig */,
|
||||
FE066D193740042A640E4E50 /* Pods-ImageNotification.release.xcconfig */,
|
||||
C9A446482226EB46FF708884 /* Pods-ImageNotification.profile.xcconfig */,
|
||||
AB50C11FF4EFC5D9961D1031 /* Pods-Runner.debug.xcconfig */,
|
||||
ACE755908B540FD8855E4D89 /* Pods-Runner.release.xcconfig */,
|
||||
1AEC3393F733CF63CC471C78 /* Pods-Runner.profile.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
@@ -208,7 +208,7 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
B7F9B35AFB424DACC3F5FE98 /* [CP] Check Pods Manifest.lock */,
|
||||
3485969F7F1D5F22AA9F93DD /* [CP] Check Pods Manifest.lock */,
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
@@ -216,9 +216,8 @@
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
9C7092B825E77E470056AE0B /* Embed App Extensions */,
|
||||
9CF1F8FD25F2A02100D93ED1 /* Firebase Crashlytics */,
|
||||
6D0F2A4EFEF187992207F8A9 /* [CP] Embed Pods Frameworks */,
|
||||
002D86FC0B93B0FCE4CC4735 /* [CP] Copy Pods Resources */,
|
||||
FEF0F5B439D2594CBDB93362 /* [CP] Embed Pods Frameworks */,
|
||||
71292F5AA25ED2C228C6EFFB /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -234,7 +233,7 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 9C7092BC25E77E470056AE0B /* Build configuration list for PBXNativeTarget "ImageNotification" */;
|
||||
buildPhases = (
|
||||
9C183B3B1872F82EEDC35FDC /* [CP] Check Pods Manifest.lock */,
|
||||
5FBBFCF3DA2647B52FD6E1AE /* [CP] Check Pods Manifest.lock */,
|
||||
9C7092AB25E77E470056AE0B /* Sources */,
|
||||
9C7092AC25E77E470056AE0B /* Frameworks */,
|
||||
9C7092AD25E77E470056AE0B /* Resources */,
|
||||
@@ -260,11 +259,13 @@
|
||||
TargetAttributes = {
|
||||
97C146ED1CF9000F007C117D = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
DevelopmentTeam = VPH33JQH4R;
|
||||
LastSwiftMigration = 1100;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
9C7092AE25E77E470056AE0B = {
|
||||
CreatedOnToolsVersion = 12.4;
|
||||
DevelopmentTeam = VPH33JQH4R;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
@@ -311,22 +312,26 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
002D86FC0B93B0FCE4CC4735 /* [CP] Copy Pods Resources */ = {
|
||||
3485969F7F1D5F22AA9F93DD /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh",
|
||||
"${PODS_ROOT}/FirebaseFirestore/FirebaseFirestore/Resources/gRPCCertificates-Cpp.bundle",
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates-Cpp.bundle",
|
||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
@@ -343,85 +348,7 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
6D0F2A4EFEF187992207F8A9 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
|
||||
"${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseAuth/FirebaseAuth.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseCrashlytics/FirebaseCrashlytics.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseStorage/FirebaseStorage.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/in_app_purchase_ios/in_app_purchase_ios.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/quick_actions/quick_actions.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseAuth.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreDiagnostics.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCrashlytics.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseInstallations.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseMessaging.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseStorage.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/in_app_purchase_ios.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/quick_actions.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Run Script";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
};
|
||||
9C183B3B1872F82EEDC35FDC /* [CP] Check Pods Manifest.lock */ = {
|
||||
5FBBFCF3DA2647B52FD6E1AE /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -443,46 +370,98 @@
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
9CF1F8FD25F2A02100D93ED1 /* Firebase Crashlytics */ = {
|
||||
71292F5AA25ED2C228C6EFFB /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
|
||||
);
|
||||
name = "Firebase Crashlytics";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh",
|
||||
"${PODS_ROOT}/FirebaseFirestore/FirebaseFirestore/Resources/gRPCCertificates-Cpp.bundle",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates-Cpp.bundle",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "${PODS_ROOT}/FirebaseCrashlytics/run\n";
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
B7F9B35AFB424DACC3F5FE98 /* [CP] Check Pods Manifest.lock */ = {
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
name = "Run Script";
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
|
||||
};
|
||||
FEF0F5B439D2594CBDB93362 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
|
||||
"${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseAuth/FirebaseAuth.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseStorage/FirebaseStorage.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/in_app_purchase_ios/in_app_purchase_ios.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/path_provider_ios/path_provider_ios.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/quick_actions/quick_actions.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/shared_preferences_ios/shared_preferences_ios.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseAuth.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreDiagnostics.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseInstallations.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseMessaging.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseStorage.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/in_app_purchase_ios.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_ios.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/quick_actions.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_ios.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
@@ -720,8 +699,7 @@
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
|
||||
@@ -3,14 +3,11 @@ import Flutter
|
||||
|
||||
@UIApplicationMain
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
var flutter_native_splash = 1
|
||||
UIApplication.shared.isStatusBarHidden = false
|
||||
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
}
|
||||
|
||||
21
ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "background.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png
vendored
Normal file
|
After Width: | Height: | Size: 70 B |
@@ -1,23 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 30 KiB |
@@ -16,13 +16,19 @@
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
||||
</imageView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" image="LaunchBackground" translatesAutoresizingMaskIntoConstraints="NO" id="tWc-Dq-wcI"/>
|
||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"></imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.19607843137254902" green="0.19607843137254902" blue="0.24313725490196078" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="3T2-ad-Qdv"/>
|
||||
<constraint firstItem="tWc-Dq-wcI" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="RPx-PI-7Xg"/>
|
||||
<constraint firstItem="tWc-Dq-wcI" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="SdS-ul-q2q"/>
|
||||
<constraint firstAttribute="trailing" secondItem="tWc-Dq-wcI" secondAttribute="trailing" id="Swv-Gf-Rwn"/>
|
||||
<constraint firstAttribute="trailing" secondItem="YRO-k0-Ey4" secondAttribute="trailing" id="TQA-XW-tRk"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="duK-uY-Gun"/>
|
||||
<constraint firstItem="tWc-Dq-wcI" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="kV7-tw-vXt"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="xPn-NY-SIU"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
@@ -32,6 +38,7 @@
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="LaunchImage" width="512" height="373"/>
|
||||
<image name="LaunchImage" width="685" height="500"/>
|
||||
<image name="LaunchBackground" width="1" height="1"/>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -60,7 +60,7 @@
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<true/>
|
||||
<false/>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Packages
|
||||
export 'package:easy_localization/easy_localization.dart';
|
||||
export 'package:expandable/expandable.dart';
|
||||
export 'package:fading_edge_scrollview/fading_edge_scrollview.dart';
|
||||
export 'package:flash/flash.dart';
|
||||
export 'package:fluro/fluro.dart';
|
||||
export 'package:hive/hive.dart';
|
||||
@@ -27,4 +28,3 @@ export 'core/state.dart';
|
||||
export 'core/system.dart';
|
||||
export 'core/ui.dart';
|
||||
export 'core/utilities.dart';
|
||||
export 'core/widgets.dart';
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
@@ -6,8 +5,6 @@ enum LunaDatabaseValue {
|
||||
DRAWER_AUTOMATIC_MANAGE,
|
||||
DRAWER_MANUAL_ORDER,
|
||||
ENABLED_PROFILE,
|
||||
ENABLE_FIREBASE_ANALYTICS,
|
||||
ENABLE_FIREBASE_CRASHLYTICS,
|
||||
THEME_AMOLED,
|
||||
THEME_AMOLED_BORDER,
|
||||
THEME_IMAGE_BACKGROUND_OPACITY,
|
||||
@@ -22,6 +19,7 @@ enum LunaDatabaseValue {
|
||||
QUICK_ACTIONS_TAUTULLI,
|
||||
QUICK_ACTIONS_SEARCH,
|
||||
USE_24_HOUR_TIME,
|
||||
DEFAULT_LAUNCH_MODULE,
|
||||
}
|
||||
|
||||
class LunaDatabase extends LunaModuleDatabase {
|
||||
@@ -47,6 +45,10 @@ class LunaDatabase extends LunaModuleDatabase {
|
||||
data[value.key] =
|
||||
(LunaDatabaseValue.SELECTED_BROWSER.data as LunaBrowser).key;
|
||||
break;
|
||||
case LunaDatabaseValue.DEFAULT_LAUNCH_MODULE:
|
||||
data[value.key] =
|
||||
(LunaDatabaseValue.DEFAULT_LAUNCH_MODULE.data as LunaModule).key;
|
||||
break;
|
||||
case LunaDatabaseValue.DRAWER_MANUAL_ORDER:
|
||||
data[value.key] = LunaDrawer.moduleOrderedList()
|
||||
?.map<String>((module) => module.key)
|
||||
@@ -71,6 +73,9 @@ class LunaDatabase extends LunaModuleDatabase {
|
||||
case LunaDatabaseValue.SELECTED_BROWSER:
|
||||
value.put(LunaBrowser.APPLE_SAFARI.fromKey(config[key]));
|
||||
break;
|
||||
case LunaDatabaseValue.DEFAULT_LAUNCH_MODULE:
|
||||
value.put(LunaModule.DASHBOARD.fromKey(config[key]));
|
||||
break;
|
||||
case LunaDatabaseValue.DRAWER_MANUAL_ORDER:
|
||||
value.put(
|
||||
(config[key] as List)
|
||||
@@ -98,7 +103,7 @@ class LunaDatabase extends LunaModuleDatabase {
|
||||
extension LunaDatabaseValueExtension on LunaDatabaseValue {
|
||||
String get key {
|
||||
if (this == LunaDatabaseValue.ENABLED_PROFILE) return 'profile';
|
||||
return 'LUNASEA_${describeEnum(this)}';
|
||||
return 'LUNASEA_${this.name}';
|
||||
}
|
||||
|
||||
dynamic get data {
|
||||
@@ -136,10 +141,6 @@ extension LunaDatabaseValueExtension on LunaDatabaseValue {
|
||||
return value is bool;
|
||||
case LunaDatabaseValue.DRAWER_MANUAL_ORDER:
|
||||
return value is List;
|
||||
case LunaDatabaseValue.ENABLE_FIREBASE_ANALYTICS:
|
||||
return value is bool;
|
||||
case LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS:
|
||||
return value is bool;
|
||||
case LunaDatabaseValue.THEME_AMOLED:
|
||||
return value is bool;
|
||||
case LunaDatabaseValue.THEME_AMOLED_BORDER:
|
||||
@@ -168,6 +169,8 @@ extension LunaDatabaseValueExtension on LunaDatabaseValue {
|
||||
return value is bool;
|
||||
case LunaDatabaseValue.USE_24_HOUR_TIME:
|
||||
return value is bool;
|
||||
case LunaDatabaseValue.DEFAULT_LAUNCH_MODULE:
|
||||
return value is LunaModule;
|
||||
}
|
||||
throw Exception('Invalid LunaDatabaseValue');
|
||||
}
|
||||
@@ -187,11 +190,7 @@ extension LunaDatabaseValueExtension on LunaDatabaseValue {
|
||||
case LunaDatabaseValue.THEME_AMOLED_BORDER:
|
||||
return false;
|
||||
case LunaDatabaseValue.THEME_IMAGE_BACKGROUND_OPACITY:
|
||||
return 10;
|
||||
case LunaDatabaseValue.ENABLE_FIREBASE_ANALYTICS:
|
||||
return true;
|
||||
case LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS:
|
||||
return true;
|
||||
return 20;
|
||||
case LunaDatabaseValue.QUICK_ACTIONS_LIDARR:
|
||||
return false;
|
||||
case LunaDatabaseValue.QUICK_ACTIONS_RADARR:
|
||||
@@ -212,6 +211,8 @@ extension LunaDatabaseValueExtension on LunaDatabaseValue {
|
||||
return false;
|
||||
case LunaDatabaseValue.USE_24_HOUR_TIME:
|
||||
return false;
|
||||
case LunaDatabaseValue.DEFAULT_LAUNCH_MODULE:
|
||||
return LunaModule.DASHBOARD;
|
||||
}
|
||||
throw Exception('Invalid LunaDatabaseValue');
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ extension ScrollControllerExtension on ScrollController {
|
||||
this.animateTo(
|
||||
0.00,
|
||||
duration: const Duration(milliseconds: LunaUI.ANIMATION_SPEED * 2),
|
||||
curve: Curves.decelerate,
|
||||
curve: Curves.easeInOutQuart,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
@@ -103,4 +104,15 @@ extension StringLinksExtension on String {
|
||||
/// Attach this string as a series ID to TVMaze and attempt to launch it as a URL.
|
||||
Future<void> lunaOpenTVMaze() async =>
|
||||
await _openLink('https://www.tvmaze.com/shows/$this');
|
||||
|
||||
Future<void> copyToClipboard({
|
||||
bool showSnackBar = true,
|
||||
}) async {
|
||||
await Clipboard.setData(ClipboardData(text: this));
|
||||
if (showSnackBar)
|
||||
showLunaSuccessSnackBar(
|
||||
title: 'Copied',
|
||||
message: 'Copied content to the clipboard',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
export 'firebase/analytics.dart';
|
||||
export 'firebase/auth.dart';
|
||||
export 'firebase/core.dart';
|
||||
export 'firebase/crashlytics.dart';
|
||||
export 'firebase/firestore.dart';
|
||||
export 'firebase/messaging.dart';
|
||||
export 'firebase/storage.dart';
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:firebase_analytics/firebase_analytics.dart';
|
||||
import 'package:firebase_analytics/observer.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LunaFirebaseAnalytics {
|
||||
/// Returns true if Firebase Analytics is compatible with this build system/platform.
|
||||
static bool get isPlatformCompatible {
|
||||
return LunaFirebase.isPlatformCompatible &&
|
||||
!Platform.isLinux &&
|
||||
!Platform.isMacOS &&
|
||||
!Platform.isWindows;
|
||||
}
|
||||
|
||||
/// Returns an instance of [FirebaseAnalytics].
|
||||
///
|
||||
/// Throws an error if [LunaFirebase.initialize] has not been called.
|
||||
static FirebaseAnalytics get instance => FirebaseAnalytics();
|
||||
|
||||
/// Returns an instance of [FirebaseAnalyticsObserver].
|
||||
///
|
||||
/// Throws an error if [LunaFirebase.initialize] has not been called.
|
||||
static FirebaseAnalyticsObserver get observer =>
|
||||
FirebaseAnalyticsObserver(analytics: instance);
|
||||
|
||||
/// Set the enabled state of Firebase Analytics.
|
||||
///
|
||||
/// If `enabled` is set to false, force-disables Analytics.
|
||||
void setEnabledState() {
|
||||
if (isPlatformCompatible) {
|
||||
bool state = LunaDatabaseValue.ENABLE_FIREBASE_ANALYTICS.data;
|
||||
instance.setAnalyticsCollectionEnabled(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// Log an "app_open" event.
|
||||
Future<void> appOpened() async {
|
||||
if (isPlatformCompatible) instance.logAppOpen();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
|
||||
class LunaFirebase {
|
||||
/// Return an instance of [FirebaseApp].
|
||||
///
|
||||
/// Throws an error if [LunaFirebase.initialize] has not been called.
|
||||
static FirebaseApp get instance => Firebase.app();
|
||||
|
||||
/// Returns true if Firebase in its entirety is compatible with this build system/platform.
|
||||
static bool get isPlatformCompatible =>
|
||||
Platform.isIOS || Platform.isAndroid || Platform.isMacOS;
|
||||
@@ -15,6 +9,5 @@ class LunaFirebase {
|
||||
/// Initialize Firebase and configuration.
|
||||
///
|
||||
/// This must be called before anything accesses Firebase services, or an exception will be thrown.
|
||||
Future<void> initialize({String name}) async =>
|
||||
await Firebase.initializeApp();
|
||||
Future<void> initialize() async => await Firebase.initializeApp();
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import 'dart:io';
|
||||
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LunaFirebaseCrashlytics {
|
||||
/// Returns true if Firebase Analytics is compatible with this build system/platform.
|
||||
static bool get isPlatformCompatible {
|
||||
return LunaFirebase.isPlatformCompatible &&
|
||||
!Platform.isLinux &&
|
||||
!Platform.isMacOS &&
|
||||
!Platform.isWindows;
|
||||
}
|
||||
|
||||
/// Returns an instance of [FirebaseCrashlytics].
|
||||
///
|
||||
/// Throws an error if [LunaFirebase.initialize] has not been called.
|
||||
static FirebaseCrashlytics get instance => FirebaseCrashlytics.instance;
|
||||
|
||||
/// Set the enabled state of Firebase Crashlytics.
|
||||
///
|
||||
/// If `enabled` is set to false, force-disables Analytics.
|
||||
void setEnabledState() {
|
||||
if (isPlatformCompatible) {
|
||||
bool state =
|
||||
kReleaseMode && LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS.data;
|
||||
instance.setCrashlyticsCollectionEnabled(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
lib/core/firebase/firebase_options.dart.gpg
Normal file
@@ -67,7 +67,7 @@ class LunaFirebaseMessaging {
|
||||
/// Return a [StreamSubscription] that will show a notification banner on a newly received notification.
|
||||
///
|
||||
/// This listens on [FirebaseMessaging.onMessage], where the application must be open and in the foreground.
|
||||
StreamSubscription<RemoteMessage> onMessageListener() {
|
||||
StreamSubscription<RemoteMessage> registerOnMessageListener() {
|
||||
return onMessage.listen((message) {
|
||||
if (message == null) return;
|
||||
LunaModule module = (message.data ?? {}).isNotEmpty
|
||||
@@ -88,7 +88,7 @@ class LunaFirebaseMessaging {
|
||||
/// Returns a [StreamSubscription] that will handle messages/notifications that are opened while LunaSea is running in the background.
|
||||
///
|
||||
/// This listens on [FirebaseMessaging.onMessageOpenedApp], where the application must be open but in the background.
|
||||
StreamSubscription<RemoteMessage> onMessageOpenedAppListener() =>
|
||||
StreamSubscription<RemoteMessage> registerOnMessageOpenedAppListener() =>
|
||||
onMessageOpenedApp.listen(_handleWebhook);
|
||||
|
||||
/// Check to see if there was an initial [RemoteMessage] available to be accessed.
|
||||
|
||||
@@ -533,7 +533,7 @@ extension LunaModuleExtension on LunaModule {
|
||||
case LunaModule.WAKE_ON_LAN:
|
||||
return 'Wake on LAN is an industry standard protocol for waking computers up from a very low power mode remotely by sending a specially constructed packet to the machine.';
|
||||
case LunaModule.EXTERNAL_MODULES:
|
||||
return 'LunaSea allows you to add additional modules that are not currently supported directly within the application, allowing you to open the module\'s web GUI without having to leave LunaSea!';
|
||||
return 'LunaSea allows you to add links to additional modules that are not currently supported allowing you to open the module\'s web GUI without having to leave LunaSea!';
|
||||
}
|
||||
throw Exception('Invalid LunaModule');
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/main.dart';
|
||||
import 'package:lunasea/modules.dart';
|
||||
|
||||
class LunaRouter {
|
||||
@@ -16,6 +17,12 @@ class LunaRouter {
|
||||
router.notFoundHandler = Handler(
|
||||
handlerFunc: (context, params) => LunaInvalidRoute(),
|
||||
);
|
||||
router.define(
|
||||
'/',
|
||||
handler: Handler(handlerFunc: (context, params) => const LunaOS()),
|
||||
transitionType: transitionType,
|
||||
);
|
||||
// Module routers
|
||||
DashboardRouter().defineAllRoutes(router);
|
||||
ExternalModulesRouter().defineAllRoutes(router);
|
||||
OverseerrRouter().defineAllRoutes(router);
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:window_size/window_size.dart' as window_size;
|
||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||
|
||||
class LunaDesktopWindow {
|
||||
static const double _MINIMUM_WINDOW_SIZE = 400;
|
||||
static const double _INITIAL_WINDOW_SIZE = 700;
|
||||
|
||||
static bool get isPlatformCompatible =>
|
||||
Platform.isWindows || Platform.isMacOS || Platform.isLinux;
|
||||
|
||||
/// Initialize the Desktop window:
|
||||
/// - Sets the minimum window size
|
||||
void initialize() {
|
||||
if (isPlatformCompatible) {
|
||||
window_size.setWindowMinSize(
|
||||
const Size(_MINIMUM_WINDOW_SIZE, _MINIMUM_WINDOW_SIZE),
|
||||
);
|
||||
doWhenWindowReady(() {
|
||||
const Size minSize = Size(_MINIMUM_WINDOW_SIZE, _MINIMUM_WINDOW_SIZE);
|
||||
const Size size = Size(_INITIAL_WINDOW_SIZE, _INITIAL_WINDOW_SIZE);
|
||||
|
||||
final win = appWindow;
|
||||
win.minSize = minSize;
|
||||
win.size = size;
|
||||
win.alignment = Alignment.center;
|
||||
win.title = "LunaSea";
|
||||
win.show();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ class LunaProfile {
|
||||
List<String> profilesList() => Database.profilesBox.keys
|
||||
.map<String>((profile) => profile as String)
|
||||
.toList()
|
||||
..sort((a, b) => a.toLowerCase().compareTo(b.toLowerCase()));
|
||||
..sort((a, b) => a.toLowerCase().compareTo(b.toLowerCase()));
|
||||
|
||||
/// Safely change profiles.
|
||||
///
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
export 'ui/appbar.dart';
|
||||
export 'ui/banner.dart';
|
||||
export 'ui/block.dart';
|
||||
export 'ui/bottom_bar.dart';
|
||||
export 'ui/bottom_modal_sheet.dart';
|
||||
export 'ui/button.dart';
|
||||
@@ -18,6 +19,7 @@ export 'ui/header.dart';
|
||||
export 'ui/highlighted_node.dart';
|
||||
export 'ui/icons.dart';
|
||||
export 'ui/input_bar.dart';
|
||||
export 'ui/linear_indicator.dart';
|
||||
export 'ui/list_tile.dart';
|
||||
export 'ui/list_view.dart';
|
||||
export 'ui/loader.dart';
|
||||
@@ -30,6 +32,7 @@ export 'ui/shape.dart';
|
||||
export 'ui/snackbar.dart';
|
||||
export 'ui/switch.dart';
|
||||
export 'ui/table.dart';
|
||||
export 'ui/text_span.dart';
|
||||
export 'ui/text.dart';
|
||||
export 'ui/theme.dart';
|
||||
export 'ui/will_pop_scope.dart';
|
||||
@@ -40,37 +43,69 @@ class LunaUI {
|
||||
static const String TEXT_ARROW_LEFT = '←';
|
||||
static const String TEXT_ARROW_RIGHT = '→';
|
||||
static const String TEXT_BULLET = '•';
|
||||
static const String TEXT_OBFUSCATED_PASSWORD = '••••••••••';
|
||||
static const String TEXT_OBFUSCATED_PASSWORD = '••••••••••••';
|
||||
static const String TEXT_ELLIPSIS = '…';
|
||||
static const String TEXT_EMDASH = '—';
|
||||
// Font-Related
|
||||
static const double FONT_SIZE_APP_BAR = 18.0;
|
||||
static const double FONT_SIZE_BUTTON = 14.0;
|
||||
static const double FONT_SIZE_GRAPH_LEGEND = 10.0;
|
||||
static const double FONT_SIZE_HEADER = 18.0;
|
||||
static const double FONT_SIZE_HIGHLIGHTED_NODE = 12.0;
|
||||
static const double FONT_SIZE_MESSAGES = 16.0;
|
||||
static const double FONT_SIZE_NAVIGATION_BAR = 13.0;
|
||||
static const double FONT_SIZE_SUBHEADER = 12.0;
|
||||
static const double FONT_SIZE_SUBTITLE = 13.0;
|
||||
static const double FONT_SIZE_TITLE = 16.0;
|
||||
static const FontWeight FONT_WEIGHT_BOLD = FontWeight.w600;
|
||||
// UI-Related
|
||||
|
||||
// <--> Font Sizes
|
||||
static const double FONT_SIZE_H1 = 18.0;
|
||||
static const double FONT_SIZE_H2 = 16.0;
|
||||
static const double FONT_SIZE_H3 = 14.0;
|
||||
static const double FONT_SIZE_H4 = 12.0;
|
||||
static const double FONT_SIZE_H5 = 10.0;
|
||||
|
||||
// <--> Font Size Mappings
|
||||
static const double FONT_SIZE_BUTTON = FONT_SIZE_H3;
|
||||
static const double FONT_SIZE_GRAPH_LEGEND = FONT_SIZE_H5;
|
||||
static const double FONT_SIZE_HEADER = FONT_SIZE_H2;
|
||||
static const double FONT_SIZE_MESSAGES = FONT_SIZE_H2;
|
||||
static const double FONT_SIZE_SUBHEADER = FONT_SIZE_H3;
|
||||
static const double FONT_SIZE_SUBTITLE = FONT_SIZE_H3;
|
||||
static const double FONT_SIZE_TITLE = FONT_SIZE_H2;
|
||||
|
||||
// <--> Icons
|
||||
static const double ICON_SIZE = 24.0;
|
||||
|
||||
// <--> Other
|
||||
static const int ANIMATION_SPEED = 250;
|
||||
static const int ANIMATION_IMAGE_FADE_IN_SPEED = 125;
|
||||
static const int ANIMATION_SPEED_IMAGES = 175;
|
||||
static const double BORDER_RADIUS = 10.0;
|
||||
static const double BUTTON_BACKGROUND_OPACITY = 0.80;
|
||||
static const double OPACITY_DIMMED = 0.75;
|
||||
static const double OPACITY_DISABLED = 0.50;
|
||||
static const double OPACITY_SPLASH = 0.25;
|
||||
static const double ELEVATION = 0.0;
|
||||
static const FontWeight FONT_WEIGHT_BOLD = FontWeight.w600;
|
||||
|
||||
// <--> Margins
|
||||
static const double DEFAULT_MARGIN_SIZE = 12.0;
|
||||
static const double MARGIN_SIZE_HALF = DEFAULT_MARGIN_SIZE / 2;
|
||||
|
||||
static const EdgeInsets MARGIN_DEFAULT = EdgeInsets.all(DEFAULT_MARGIN_SIZE);
|
||||
static const EdgeInsets MARGIN_CARD = EdgeInsets.symmetric(
|
||||
horizontal: DEFAULT_MARGIN_SIZE,
|
||||
vertical: DEFAULT_MARGIN_SIZE / 2,
|
||||
);
|
||||
// Border-Related
|
||||
static bool get shouldUseBorder =>
|
||||
LunaTheme.isAMOLEDTheme && LunaTheme.useAMOLEDBorders;
|
||||
static ShapeBorder get shapeBorder => shouldUseBorder
|
||||
? LunaShapeBorder.roundedWithBorder()
|
||||
: LunaShapeBorder.rounded();
|
||||
static const EdgeInsets MARGIN_HALF = EdgeInsets.all(MARGIN_SIZE_HALF);
|
||||
|
||||
static const EdgeInsets MARGIN_DEFAULT_HORIZONTAL =
|
||||
EdgeInsets.symmetric(horizontal: DEFAULT_MARGIN_SIZE);
|
||||
static const EdgeInsets MARGIN_DEFAULT_VERTICAL =
|
||||
EdgeInsets.symmetric(vertical: DEFAULT_MARGIN_SIZE);
|
||||
|
||||
static const EdgeInsets MARGIN_HALF_HORIZONTAL =
|
||||
EdgeInsets.symmetric(horizontal: MARGIN_SIZE_HALF);
|
||||
static const EdgeInsets MARGIN_HALF_VERTICAL =
|
||||
EdgeInsets.symmetric(vertical: MARGIN_SIZE_HALF);
|
||||
|
||||
static const EdgeInsets MARGIN_H_DEFAULT_V_HALF = EdgeInsets.symmetric(
|
||||
horizontal: DEFAULT_MARGIN_SIZE, vertical: MARGIN_SIZE_HALF);
|
||||
static const EdgeInsets MARGIN_H_HALF_V_DEFAULT = EdgeInsets.symmetric(
|
||||
horizontal: MARGIN_SIZE_HALF, vertical: DEFAULT_MARGIN_SIZE);
|
||||
|
||||
// <--> Borders
|
||||
static bool get shouldUseBorder {
|
||||
return LunaTheme.isAMOLEDTheme && LunaTheme.useAMOLEDBorders;
|
||||
}
|
||||
|
||||
static ShapeBorder get shapeBorder {
|
||||
return shouldUseBorder
|
||||
? LunaShapeBorder.roundedWithBorder()
|
||||
: LunaShapeBorder.rounded();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,12 @@ class LunaAppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
final List<String> profiles;
|
||||
final PageController pageController;
|
||||
final List<ScrollController> scrollControllers;
|
||||
final Color backgroundColor;
|
||||
|
||||
@override
|
||||
Size get preferredSize {
|
||||
double _size = (height ?? APPBAR_HEIGHT);
|
||||
if (bottom != null) _size += bottom.preferredSize.height;
|
||||
if (bottom != null) _size += bottom.preferredSize.height - 0.0;
|
||||
return Size.fromHeight(_size);
|
||||
}
|
||||
|
||||
@@ -42,6 +43,7 @@ class LunaAppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
this.pageController,
|
||||
this.scrollControllers,
|
||||
this.hideLeading = false,
|
||||
this.backgroundColor,
|
||||
});
|
||||
|
||||
/// Create a new [AppBar] widget pre-styled for LunaSea.
|
||||
@@ -58,6 +60,7 @@ class LunaAppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
bool useDrawer = false,
|
||||
bool hideLeading = false,
|
||||
PageController pageController,
|
||||
Color backgroundColor,
|
||||
List<ScrollController> scrollControllers,
|
||||
}) {
|
||||
assert(title != null);
|
||||
@@ -72,6 +75,7 @@ class LunaAppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
pageController: pageController,
|
||||
scrollControllers: scrollControllers,
|
||||
hideLeading: hideLeading,
|
||||
backgroundColor: backgroundColor,
|
||||
type: _APPBAR_TYPE.DEFAULT,
|
||||
);
|
||||
}
|
||||
@@ -86,6 +90,7 @@ class LunaAppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
@required double height,
|
||||
EdgeInsets padding = LunaTextInputBar.appBarMargin,
|
||||
Alignment alignment = Alignment.topCenter,
|
||||
Color backgroundColor,
|
||||
}) {
|
||||
assert(child != null);
|
||||
assert(height != null);
|
||||
@@ -98,6 +103,7 @@ class LunaAppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
),
|
||||
height: height,
|
||||
useDrawer: false,
|
||||
backgroundColor: backgroundColor,
|
||||
type: _APPBAR_TYPE.EMPTY,
|
||||
);
|
||||
}
|
||||
@@ -117,6 +123,8 @@ class LunaAppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
List<Widget> actions,
|
||||
PageController pageController,
|
||||
List<ScrollController> scrollControllers,
|
||||
PreferredSizeWidget bottom,
|
||||
Color backgroundColor,
|
||||
}) {
|
||||
assert(title != null);
|
||||
assert(profiles != null);
|
||||
@@ -129,18 +137,22 @@ class LunaAppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
actions: actions,
|
||||
useDrawer: useDrawer,
|
||||
hideLeading: hideLeading,
|
||||
bottom: bottom,
|
||||
pageController: pageController,
|
||||
scrollControllers: scrollControllers,
|
||||
backgroundColor: backgroundColor,
|
||||
type: _APPBAR_TYPE.DEFAULT,
|
||||
);
|
||||
return LunaAppBar._internal(
|
||||
title: title,
|
||||
profiles: profiles,
|
||||
actions: actions,
|
||||
bottom: bottom,
|
||||
useDrawer: useDrawer,
|
||||
hideLeading: hideLeading,
|
||||
pageController: pageController,
|
||||
scrollControllers: scrollControllers,
|
||||
backgroundColor: backgroundColor,
|
||||
type: _APPBAR_TYPE.DROPDOWN,
|
||||
);
|
||||
}
|
||||
@@ -210,38 +222,36 @@ class _State extends State<LunaAppBar> {
|
||||
Widget _sharedLeading(BuildContext context) {
|
||||
if (widget.hideLeading ?? false) return null;
|
||||
if (widget.useDrawer)
|
||||
return IconButton(
|
||||
icon: const Icon(Icons.menu_rounded),
|
||||
onPressed: () async {
|
||||
HapticFeedback.lightImpact();
|
||||
if (Scaffold.of(context).hasDrawer) {
|
||||
Scaffold.of(context).openDrawer();
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
}
|
||||
},
|
||||
return SizedBox(
|
||||
child: LunaIconButton.appBar(
|
||||
icon: Icons.menu_rounded,
|
||||
onPressed: () async {
|
||||
HapticFeedback.lightImpact();
|
||||
if (Scaffold.of(context).hasDrawer) {
|
||||
Scaffold.of(context).openDrawer();
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
}
|
||||
},
|
||||
),
|
||||
height: kToolbarHeight,
|
||||
);
|
||||
return InkWell(
|
||||
child: const Center(
|
||||
child: Icon(Icons.arrow_back_ios_new_rounded),
|
||||
return SizedBox(
|
||||
child: LunaIconButton.appBar(
|
||||
icon: Icons.arrow_back_ios_new_rounded,
|
||||
onPressed: () async => Navigator.of(context).lunaSafetyPop(),
|
||||
onLongPress: () async => Navigator.of(context).lunaPopToFirst(),
|
||||
),
|
||||
onTap: () async {
|
||||
HapticFeedback.lightImpact();
|
||||
Navigator.of(context).lunaSafetyPop();
|
||||
},
|
||||
onLongPress: () async {
|
||||
HapticFeedback.heavyImpact();
|
||||
Navigator.of(context).lunaPopToFirst();
|
||||
},
|
||||
borderRadius: BorderRadius.circular(28.0),
|
||||
height: kToolbarHeight,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _default(BuildContext context) {
|
||||
return AppBar(
|
||||
backgroundColor: widget.backgroundColor,
|
||||
title: Text(
|
||||
widget.title ?? '',
|
||||
overflow: TextOverflow.fade,
|
||||
style: const TextStyle(fontSize: LunaUI.FONT_SIZE_APP_BAR),
|
||||
style: const TextStyle(fontSize: LunaUI.FONT_SIZE_H1),
|
||||
),
|
||||
leading: _sharedLeading(context),
|
||||
automaticallyImplyLeading: !(widget.hideLeading ?? false),
|
||||
@@ -254,6 +264,7 @@ class _State extends State<LunaAppBar> {
|
||||
|
||||
Widget _empty(BuildContext context) {
|
||||
return AppBar(
|
||||
backgroundColor: widget.backgroundColor,
|
||||
automaticallyImplyLeading: false,
|
||||
toolbarHeight: widget.height,
|
||||
leadingWidth: 0.0,
|
||||
@@ -265,15 +276,24 @@ class _State extends State<LunaAppBar> {
|
||||
|
||||
Widget _dropdown(BuildContext context) {
|
||||
return AppBar(
|
||||
backgroundColor: widget.backgroundColor,
|
||||
automaticallyImplyLeading: !(widget.hideLeading ?? false),
|
||||
title: LunaPopupMenuButton<String>(
|
||||
tooltip: 'Change Profiles',
|
||||
child: Wrap(
|
||||
direction: Axis.horizontal,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
widget.title,
|
||||
style: const TextStyle(fontSize: LunaUI.FONT_SIZE_HEADER),
|
||||
Flexible(
|
||||
child: FadingEdgeScrollView.fromSingleChildScrollView(
|
||||
child: SingleChildScrollView(
|
||||
controller: ScrollController(),
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Text(
|
||||
widget.title,
|
||||
style: const TextStyle(fontSize: LunaUI.FONT_SIZE_H1),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const Icon(Icons.arrow_drop_down_rounded),
|
||||
],
|
||||
@@ -290,7 +310,7 @@ class _State extends State<LunaAppBar> {
|
||||
child: Text(
|
||||
profile,
|
||||
style: TextStyle(
|
||||
fontSize: LunaUI.FONT_SIZE_SUBTITLE,
|
||||
fontSize: LunaUI.FONT_SIZE_H3,
|
||||
color:
|
||||
(LunaDatabaseValue.ENABLED_PROFILE.data ?? 'default') ==
|
||||
profile
|
||||
@@ -306,6 +326,7 @@ class _State extends State<LunaAppBar> {
|
||||
centerTitle: false,
|
||||
elevation: 0,
|
||||
actions: widget.actions,
|
||||
bottom: widget.bottom,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class LunaBanner extends StatelessWidget {
|
||||
this.iconColor = LunaColours.accent,
|
||||
this.backgroundColor,
|
||||
this.headerColor = Colors.white,
|
||||
this.bodyColor = Colors.white70,
|
||||
this.bodyColor = LunaColours.grey,
|
||||
this.buttons,
|
||||
}) : super(key: key);
|
||||
|
||||
@@ -32,12 +32,13 @@ class LunaBanner extends StatelessWidget {
|
||||
return LunaCard(
|
||||
context: context,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: LunaUI.MARGIN_CARD.top),
|
||||
padding:
|
||||
EdgeInsets.symmetric(vertical: LunaUI.MARGIN_H_DEFAULT_V_HALF.top),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: LunaUI.MARGIN_CARD,
|
||||
padding: LunaUI.MARGIN_H_DEFAULT_V_HALF,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
@@ -73,7 +74,7 @@ class LunaBanner extends StatelessWidget {
|
||||
),
|
||||
if (bodyText?.isNotEmpty ?? false)
|
||||
Padding(
|
||||
padding: LunaUI.MARGIN_CARD.copyWith(top: 0),
|
||||
padding: LunaUI.MARGIN_H_DEFAULT_V_HALF.copyWith(top: 0),
|
||||
child: LunaText.subtitle(
|
||||
text: bodyText.toString(),
|
||||
color: bodyColor,
|
||||
@@ -84,7 +85,7 @@ class LunaBanner extends StatelessWidget {
|
||||
if (buttons?.isNotEmpty ?? false)
|
||||
LunaButtonContainer(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: LunaUI.MARGIN_CARD.left / 2),
|
||||
horizontal: LunaUI.MARGIN_H_DEFAULT_V_HALF.left / 2),
|
||||
children: buttons,
|
||||
),
|
||||
],
|
||||
|
||||
302
lib/core/ui/block.dart
Normal file
@@ -0,0 +1,302 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:transparent_image/transparent_image.dart';
|
||||
|
||||
class LunaBlock extends StatelessWidget {
|
||||
static const TITLE_HEIGHT = LunaUI.FONT_SIZE_H2 + 4.0;
|
||||
static const SUBTITLE_HEIGHT = LunaUI.FONT_SIZE_H3 + 4.0;
|
||||
|
||||
final bool disabled;
|
||||
final String title;
|
||||
final Color titleColor;
|
||||
|
||||
/// If defined, only takes the first body subtitle from the [body] array
|
||||
/// And allows that single [TextSpan] to overflow to this many lines
|
||||
final int customBodyMaxLines;
|
||||
final List<TextSpan> body;
|
||||
|
||||
/// Icons that lead the body lines. If defined, then the length of this list
|
||||
/// must match the length of [body]. If a specific line does not need a
|
||||
/// leading icon, pass in null.
|
||||
final List<IconData> bodyLeadingIcons;
|
||||
final Color bodyLeadingIconsColor;
|
||||
|
||||
final Widget leading;
|
||||
final Widget trailing;
|
||||
final Widget bottom;
|
||||
final double bottomHeight;
|
||||
|
||||
final Function onTap;
|
||||
final Function onLongPress;
|
||||
|
||||
final IconData posterPlaceholderIcon;
|
||||
final String posterUrl;
|
||||
final Map posterHeaders;
|
||||
final bool posterIsSquare;
|
||||
final String backgroundUrl;
|
||||
final Map backgroundHeaders;
|
||||
|
||||
const LunaBlock({
|
||||
Key key,
|
||||
this.disabled = false,
|
||||
@required this.title,
|
||||
this.titleColor = Colors.white,
|
||||
this.body,
|
||||
this.bodyLeadingIcons,
|
||||
this.bodyLeadingIconsColor = LunaColours.accent,
|
||||
this.bottom,
|
||||
this.bottomHeight = SUBTITLE_HEIGHT,
|
||||
this.customBodyMaxLines,
|
||||
this.posterPlaceholderIcon,
|
||||
this.posterUrl,
|
||||
this.posterHeaders = const {},
|
||||
this.posterIsSquare = false,
|
||||
this.backgroundUrl,
|
||||
this.backgroundHeaders = const {},
|
||||
this.onTap,
|
||||
this.onLongPress,
|
||||
this.leading,
|
||||
this.trailing,
|
||||
}) : super(key: key);
|
||||
|
||||
static double calculateItemExtent(
|
||||
int subtitleLines, {
|
||||
bool hasBottom = false,
|
||||
double bottomHeight = SUBTITLE_HEIGHT,
|
||||
}) {
|
||||
double height = calculateItemHeight(
|
||||
subtitleLines,
|
||||
hasBottom: hasBottom,
|
||||
bottomHeight: bottomHeight,
|
||||
);
|
||||
return height + LunaUI.MARGIN_H_DEFAULT_V_HALF.vertical;
|
||||
}
|
||||
|
||||
static double calculateItemHeight(
|
||||
int subtitleLines, {
|
||||
bool hasBottom = false,
|
||||
double bottomHeight = SUBTITLE_HEIGHT,
|
||||
}) {
|
||||
double height = (LunaUI.DEFAULT_MARGIN_SIZE * 2) + TITLE_HEIGHT;
|
||||
height += subtitleLines * SUBTITLE_HEIGHT;
|
||||
if (hasBottom) height += bottomHeight;
|
||||
return height;
|
||||
}
|
||||
|
||||
double _calculateHeight() {
|
||||
int _scalar = customBodyMaxLines;
|
||||
_scalar ??= body?.length ?? 0;
|
||||
return calculateItemHeight(
|
||||
_scalar,
|
||||
hasBottom: bottom != null,
|
||||
bottomHeight: bottomHeight,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
double _height = _calculateHeight();
|
||||
return LunaCard(
|
||||
context: context,
|
||||
child: InkWell(
|
||||
child: Stack(
|
||||
children: [
|
||||
if (backgroundUrl?.isNotEmpty ?? false)
|
||||
_fadeInBackground(context, _height),
|
||||
Opacity(
|
||||
opacity: disabled ? LunaUI.OPACITY_DISABLED : 1.0,
|
||||
child: Row(
|
||||
children: [
|
||||
_poster(context, _height),
|
||||
_tile(context, _height),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
mouseCursor: onTap != null || onLongPress != null
|
||||
? SystemMouseCursors.click
|
||||
: MouseCursor.defer,
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
),
|
||||
height: _height,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _fadeInBackground(BuildContext context, double _height) {
|
||||
int _percent = LunaDatabaseValue.THEME_IMAGE_BACKGROUND_OPACITY.data as int;
|
||||
if (_percent == 0) return const SizedBox(height: 0, width: 0);
|
||||
|
||||
double _opacity = _percent / 100;
|
||||
if (disabled) _opacity *= LunaUI.OPACITY_DISABLED;
|
||||
|
||||
return Opacity(
|
||||
opacity: _opacity,
|
||||
child: FadeInImage(
|
||||
placeholder: MemoryImage(kTransparentImage),
|
||||
height: _height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
fadeInDuration: const Duration(
|
||||
milliseconds: LunaUI.ANIMATION_SPEED_IMAGES,
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
image: NetworkImage(
|
||||
backgroundUrl,
|
||||
headers: backgroundHeaders?.cast<String, String>(),
|
||||
),
|
||||
imageErrorBuilder: (context, error, stack) => SizedBox(
|
||||
height: _height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _poster(BuildContext context, double height) {
|
||||
if (posterUrl == null && posterPlaceholderIcon == null) {
|
||||
return const SizedBox(width: 0.0, height: 0.0);
|
||||
}
|
||||
|
||||
double _dimension = height - LunaUI.DEFAULT_MARGIN_SIZE;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: LunaUI.DEFAULT_MARGIN_SIZE / 2),
|
||||
child: LunaNetworkImage(
|
||||
context: context,
|
||||
url: posterUrl ?? '',
|
||||
headers: posterHeaders,
|
||||
placeholderIcon: posterPlaceholderIcon,
|
||||
height: _dimension,
|
||||
width: _dimension / (posterIsSquare ? 1.0 : 1.5),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _tile(BuildContext context, double height) {
|
||||
return Expanded(
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
child: LunaListTile(
|
||||
context: context,
|
||||
title: _scrollableText(
|
||||
child: LunaText.title(
|
||||
text: title,
|
||||
color: titleColor,
|
||||
overflow: TextOverflow.visible,
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
subtitle: _subtitle(),
|
||||
color: Colors.transparent,
|
||||
margin: EdgeInsets.zero,
|
||||
drawBorder: false,
|
||||
height: height,
|
||||
trailing: trailing,
|
||||
leading: leading,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _subtitle() {
|
||||
int maxLines = customBodyMaxLines ?? 1;
|
||||
double height = SUBTITLE_HEIGHT * maxLines;
|
||||
|
||||
if (bodyLeadingIcons != null) {
|
||||
assert(
|
||||
bodyLeadingIcons.length == body?.length,
|
||||
'bodyLeadingIcons and body should be the same size',
|
||||
);
|
||||
}
|
||||
|
||||
Widget _wrapper(List<Widget> children) {
|
||||
return Expanded(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: children,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _entry(TextSpan textSpan, IconData icon) {
|
||||
return SizedBox(
|
||||
height: height,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (icon != null)
|
||||
Padding(
|
||||
child: Container(
|
||||
child: Icon(
|
||||
icon,
|
||||
color: bodyLeadingIconsColor,
|
||||
size: LunaUI.FONT_SIZE_H2,
|
||||
),
|
||||
height: SUBTITLE_HEIGHT * maxLines,
|
||||
width: SUBTITLE_HEIGHT,
|
||||
alignment: Alignment.centerLeft,
|
||||
),
|
||||
padding: const EdgeInsets.only(
|
||||
right: LunaUI.DEFAULT_MARGIN_SIZE / 4,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: _scrollableText(
|
||||
scrollDirection: maxLines > 1 ? Axis.vertical : Axis.horizontal,
|
||||
child: Container(
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
style: const TextStyle(
|
||||
fontSize: LunaUI.FONT_SIZE_H3,
|
||||
color: LunaColours.grey,
|
||||
),
|
||||
children: [textSpan],
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: maxLines == 1 ? false : true,
|
||||
maxLines: maxLines,
|
||||
),
|
||||
alignment: Alignment.centerLeft,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _children = [];
|
||||
|
||||
if (body?.isNotEmpty ?? false) {
|
||||
if (customBodyMaxLines != null) {
|
||||
_children.add(_entry(body[0], bodyLeadingIcons?.elementAtOrNull(0)));
|
||||
} else {
|
||||
for (int i = 0; i < body.length; i++) {
|
||||
_children.add(_entry(body[i], bodyLeadingIcons?.elementAtOrNull(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bottom != null) {
|
||||
_children.add(SizedBox(
|
||||
height: bottomHeight,
|
||||
child: bottom,
|
||||
));
|
||||
}
|
||||
|
||||
return _children.isEmpty ? null : _wrapper(_children);
|
||||
}
|
||||
|
||||
Widget _scrollableText({
|
||||
@required Widget child,
|
||||
Axis scrollDirection = Axis.horizontal,
|
||||
}) {
|
||||
return FadingEdgeScrollView.fromSingleChildScrollView(
|
||||
child: SingleChildScrollView(
|
||||
controller: ScrollController(),
|
||||
scrollDirection: scrollDirection,
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export 'bottom_bar/action_bar_card.dart';
|
||||
export 'bottom_bar/action_bar.dart';
|
||||
export 'bottom_bar/badge.dart';
|
||||
export 'bottom_bar/navigation_bar.dart';
|
||||
|
||||
@@ -21,7 +21,7 @@ class LunaActionBarCard extends StatelessWidget {
|
||||
this.onLongPress,
|
||||
this.backgroundColor,
|
||||
this.color = LunaColours.accent,
|
||||
this.icon = Icons.arrow_forward_ios_rounded,
|
||||
this.icon = LunaIcons.ARROW_RIGHT,
|
||||
this.checkboxState,
|
||||
this.checkboxOnChanged,
|
||||
}) : super(key: key);
|
||||
@@ -59,7 +59,7 @@ class LunaActionBarCard extends StatelessWidget {
|
||||
overflow: TextOverflow.fade,
|
||||
style: const TextStyle(
|
||||
fontSize: LunaUI.FONT_SIZE_SUBHEADER,
|
||||
color: Colors.white70,
|
||||
color: LunaColours.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -77,7 +77,7 @@ class LunaActionBarCard extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (icon != null)
|
||||
if (checkboxState == null && icon != null)
|
||||
Container(
|
||||
width: 30.0,
|
||||
alignment: Alignment.centerRight,
|
||||
@@ -96,26 +96,38 @@ class LunaActionBarCard extends StatelessWidget {
|
||||
height: LunaButton.DEFAULT_HEIGHT,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
onTap: onTap == null
|
||||
? null
|
||||
: () async {
|
||||
HapticFeedback.lightImpact();
|
||||
onTap();
|
||||
},
|
||||
onLongPress: onLongPress == null
|
||||
? null
|
||||
: () async {
|
||||
HapticFeedback.heavyImpact();
|
||||
onLongPress();
|
||||
},
|
||||
onTap: _onTapHandler(),
|
||||
onLongPress: _onLongPressHandler(),
|
||||
),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 6.0, vertical: 6.0),
|
||||
margin: LunaUI.MARGIN_HALF,
|
||||
color: backgroundColor != null
|
||||
? backgroundColor.withOpacity(LunaUI.BUTTON_BACKGROUND_OPACITY)
|
||||
? backgroundColor.withOpacity(LunaUI.OPACITY_DIMMED)
|
||||
: LunaTheme.isAMOLEDTheme
|
||||
? Colors.black.withOpacity(LunaUI.BUTTON_BACKGROUND_OPACITY)
|
||||
: LunaColours.primary
|
||||
.withOpacity(LunaUI.BUTTON_BACKGROUND_OPACITY),
|
||||
? Colors.black.withOpacity(LunaUI.OPACITY_DIMMED)
|
||||
: LunaColours.primary.withOpacity(LunaUI.OPACITY_DIMMED),
|
||||
);
|
||||
}
|
||||
|
||||
Function _onTapHandler() {
|
||||
if (onTap != null) {
|
||||
return () async {
|
||||
HapticFeedback.lightImpact();
|
||||
onTap();
|
||||
};
|
||||
}
|
||||
if (checkboxState != null && checkboxOnChanged != null) {
|
||||
return () async => checkboxOnChanged(!checkboxState);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Function _onLongPressHandler() {
|
||||
if (onLongPress != null) {
|
||||
return () async {
|
||||
HapticFeedback.heavyImpact();
|
||||
onLongPress();
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,7 @@ class LunaNavigationBarBadge extends Badge {
|
||||
@required bool isActive,
|
||||
}) : super(
|
||||
key: key,
|
||||
badgeColor:
|
||||
LunaColours.accent.withOpacity(LunaUI.BUTTON_BACKGROUND_OPACITY),
|
||||
badgeColor: LunaColours.accent.withOpacity(LunaUI.OPACITY_DIMMED),
|
||||
elevation: 0,
|
||||
animationDuration:
|
||||
const Duration(milliseconds: LunaUI.ANIMATION_SPEED),
|
||||
@@ -29,8 +28,7 @@ class LunaNavigationBarBadge extends Badge {
|
||||
child: Icon(
|
||||
icon,
|
||||
color: isActive
|
||||
? LunaColours.accent
|
||||
.withOpacity(LunaUI.BUTTON_BACKGROUND_OPACITY)
|
||||
? LunaColours.accent.withOpacity(LunaUI.OPACITY_DIMMED)
|
||||
: Colors.white,
|
||||
),
|
||||
showBadge: showBadge,
|
||||
|
||||
@@ -79,11 +79,10 @@ class _State extends State<LunaBottomNavigationBar> {
|
||||
child: Padding(
|
||||
child: GNav(
|
||||
gap: 8.0,
|
||||
iconSize: 24.0,
|
||||
duration: const Duration(milliseconds: LunaUI.ANIMATION_SPEED),
|
||||
tabBackgroundColor: Theme.of(context)
|
||||
.canvasColor
|
||||
.withOpacity(LunaUI.BUTTON_BACKGROUND_OPACITY),
|
||||
.withOpacity(LunaUI.OPACITY_DIMMED),
|
||||
activeColor: LunaColours.accent,
|
||||
tabs: List.generate(
|
||||
widget.icons.length,
|
||||
@@ -91,7 +90,7 @@ class _State extends State<LunaBottomNavigationBar> {
|
||||
icon: widget.icons[index],
|
||||
text: widget.titles[index],
|
||||
active: _index == index,
|
||||
iconSize: 22.0,
|
||||
iconSize: LunaUI.ICON_SIZE,
|
||||
haptic: true,
|
||||
padding: _index == index
|
||||
? const EdgeInsets.all(10.0)
|
||||
@@ -100,7 +99,7 @@ class _State extends State<LunaBottomNavigationBar> {
|
||||
iconColor: Colors.white,
|
||||
textStyle: const TextStyle(
|
||||
fontWeight: LunaUI.FONT_WEIGHT_BOLD,
|
||||
fontSize: LunaUI.FONT_SIZE_NAVIGATION_BAR,
|
||||
fontSize: LunaUI.FONT_SIZE_H3,
|
||||
color: Colors.white,
|
||||
),
|
||||
iconActiveColor: LunaColours.accent,
|
||||
@@ -109,7 +108,7 @@ class _State extends State<LunaBottomNavigationBar> {
|
||||
: widget.leadingOnTab[index],
|
||||
)).toList(),
|
||||
tabActiveBorder: LunaUI.shouldUseBorder
|
||||
? Border.all(color: Colors.white12)
|
||||
? Border.all(color: LunaColours.white10)
|
||||
: null,
|
||||
tabBorder: LunaUI.shouldUseBorder
|
||||
? Border.all(color: Colors.transparent)
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
|
||||
|
||||
class LunaBottomModalSheet {
|
||||
@protected
|
||||
Future<dynamic> showModal({
|
||||
@required BuildContext context,
|
||||
Widget Function(BuildContext context) builder,
|
||||
@@ -20,4 +21,13 @@ class LunaBottomModalSheet {
|
||||
}
|
||||
|
||||
Widget builder(BuildContext context) => null;
|
||||
|
||||
Future<dynamic> show({
|
||||
@required BuildContext context,
|
||||
Widget Function(BuildContext context) builder,
|
||||
}) async =>
|
||||
showModal(
|
||||
context: context,
|
||||
builder: builder,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,13 +10,12 @@ enum LunaButtonType {
|
||||
|
||||
/// A Luna-styled button.
|
||||
class LunaButton extends Card {
|
||||
static const DEFAULT_HEIGHT = 50.0;
|
||||
static const DEFAULT_HEIGHT = 46.0;
|
||||
|
||||
LunaButton._({
|
||||
Key key,
|
||||
@required Widget child,
|
||||
EdgeInsets margin =
|
||||
const EdgeInsets.symmetric(horizontal: 6.0, vertical: 6.0),
|
||||
EdgeInsets margin = LunaUI.MARGIN_HALF,
|
||||
Color backgroundColor,
|
||||
double height = DEFAULT_HEIGHT,
|
||||
Alignment alignment = Alignment.center,
|
||||
@@ -47,11 +46,10 @@ class LunaButton extends Card {
|
||||
),
|
||||
margin: margin,
|
||||
color: backgroundColor != null
|
||||
? backgroundColor.withOpacity(LunaUI.BUTTON_BACKGROUND_OPACITY)
|
||||
? backgroundColor.withOpacity(LunaUI.OPACITY_DIMMED)
|
||||
: LunaTheme.isAMOLEDTheme
|
||||
? Colors.black.withOpacity(LunaUI.BUTTON_BACKGROUND_OPACITY)
|
||||
: LunaColours.primary
|
||||
.withOpacity(LunaUI.BUTTON_BACKGROUND_OPACITY),
|
||||
? Colors.black.withOpacity(LunaUI.OPACITY_DIMMED)
|
||||
: LunaColours.primary.withOpacity(LunaUI.OPACITY_DIMMED),
|
||||
shape: backgroundColor != null
|
||||
? LunaShapeBorder.rounded()
|
||||
: LunaUI.shapeBorder,
|
||||
@@ -70,10 +68,9 @@ class LunaButton extends Card {
|
||||
Color backgroundColor,
|
||||
String text,
|
||||
IconData icon,
|
||||
double iconSize = 22.0,
|
||||
double iconSize = LunaUI.ICON_SIZE,
|
||||
LunaLoadingState loadingState,
|
||||
EdgeInsets margin =
|
||||
const EdgeInsets.symmetric(horizontal: 6.0, vertical: 6.0),
|
||||
EdgeInsets margin = LunaUI.MARGIN_HALF,
|
||||
double height = DEFAULT_HEIGHT,
|
||||
Alignment alignment = Alignment.center,
|
||||
Decoration decoration,
|
||||
@@ -163,11 +160,10 @@ class LunaButton extends Card {
|
||||
factory LunaButton.text({
|
||||
@required String text,
|
||||
@required IconData icon,
|
||||
double iconSize = 22.0,
|
||||
double iconSize = LunaUI.ICON_SIZE,
|
||||
Color color = LunaColours.accent,
|
||||
Color backgroundColor,
|
||||
EdgeInsets margin =
|
||||
const EdgeInsets.symmetric(horizontal: 6.0, vertical: 6.0),
|
||||
EdgeInsets margin = LunaUI.MARGIN_HALF,
|
||||
double height = DEFAULT_HEIGHT,
|
||||
Alignment alignment = Alignment.center,
|
||||
Decoration decoration,
|
||||
@@ -188,7 +184,8 @@ class LunaButton extends Card {
|
||||
color: color,
|
||||
size: iconSize,
|
||||
),
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
padding: const EdgeInsets.only(
|
||||
right: LunaUI.DEFAULT_MARGIN_SIZE / 2),
|
||||
),
|
||||
Flexible(
|
||||
child: Text(
|
||||
@@ -196,7 +193,7 @@ class LunaButton extends Card {
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: LunaUI.FONT_WEIGHT_BOLD,
|
||||
fontSize: LunaUI.FONT_SIZE_BUTTON,
|
||||
fontSize: LunaUI.FONT_SIZE_H3,
|
||||
),
|
||||
overflow: TextOverflow.fade,
|
||||
softWrap: false,
|
||||
@@ -205,7 +202,8 @@ class LunaButton extends Card {
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: LunaUI.DEFAULT_MARGIN_SIZE),
|
||||
),
|
||||
margin: margin,
|
||||
height: height,
|
||||
@@ -220,8 +218,7 @@ class LunaButton extends Card {
|
||||
|
||||
/// Build a button that contains a [LunaLoader].
|
||||
factory LunaButton.loader({
|
||||
EdgeInsets margin =
|
||||
const EdgeInsets.symmetric(horizontal: 6.0, vertical: 6.0),
|
||||
EdgeInsets margin = LunaUI.MARGIN_HALF,
|
||||
Color color = LunaColours.accent,
|
||||
Color backgroundColor,
|
||||
double height = DEFAULT_HEIGHT,
|
||||
@@ -235,7 +232,7 @@ class LunaButton extends Card {
|
||||
child: LunaLoader(
|
||||
useSafeArea: false,
|
||||
color: color,
|
||||
size: 16.0,
|
||||
size: LunaUI.FONT_SIZE_H3,
|
||||
),
|
||||
margin: margin,
|
||||
height: height,
|
||||
@@ -253,10 +250,9 @@ class LunaButton extends Card {
|
||||
@required IconData icon,
|
||||
Color color = LunaColours.accent,
|
||||
Color backgroundColor,
|
||||
EdgeInsets margin =
|
||||
const EdgeInsets.symmetric(horizontal: 6.0, vertical: 6.0),
|
||||
EdgeInsets margin = LunaUI.MARGIN_HALF,
|
||||
double height = DEFAULT_HEIGHT,
|
||||
double iconSize = 22.0,
|
||||
double iconSize = LunaUI.ICON_SIZE,
|
||||
Alignment alignment = Alignment.center,
|
||||
Decoration decoration,
|
||||
Function onTap,
|
||||
|
||||
@@ -6,7 +6,7 @@ class LunaCard extends Card {
|
||||
Key key,
|
||||
@required BuildContext context,
|
||||
@required Widget child,
|
||||
EdgeInsets margin = LunaUI.MARGIN_CARD,
|
||||
EdgeInsets margin = LunaUI.MARGIN_H_DEFAULT_V_HALF,
|
||||
Color color,
|
||||
Decoration decoration,
|
||||
double height,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LunaColours {
|
||||
/// List of LunaSea colours in order that the should appear in a list.
|
||||
@@ -25,20 +26,17 @@ class LunaColours {
|
||||
/// Core secondary colour (appbar, bottom bar, etc.),
|
||||
static const Color secondary = Color(0xFF282834);
|
||||
|
||||
/// Blue
|
||||
static const Color blue = Color(0xFF00A8E8);
|
||||
|
||||
/// Orange
|
||||
static const Color blueGrey = Color(0xFF848FA5);
|
||||
static const Color grey = Color(0xFFBBBBBB);
|
||||
static const Color orange = Color(0xFFFF9000);
|
||||
|
||||
/// Red
|
||||
static const Color purple = Color(0xFF9649CB);
|
||||
static const Color red = Color(0xFFF71735);
|
||||
|
||||
/// Purple
|
||||
static const Color purple = Color(0xFF9649CB);
|
||||
|
||||
/// Blue Grey
|
||||
static const Color blueGrey = Color(0xFF848FA5);
|
||||
/// Shades of White
|
||||
static const Color white = Color(0xFFFFFFFF);
|
||||
static const Color white70 = Color(0xB3FFFFFF);
|
||||
static const Color white10 = Color(0x1AFFFFFF);
|
||||
|
||||
/// Returns the correct colour for a graph by what layer it is on the graph canvas.
|
||||
Color byGraphLayer(int index) {
|
||||
@@ -60,3 +58,15 @@ class LunaColours {
|
||||
return _LIST_COLOR_ICONS[index % _LIST_COLOR_ICONS.length];
|
||||
}
|
||||
}
|
||||
|
||||
extension LunaColor on Color {
|
||||
Color disabled([bool condition = true]) {
|
||||
if (condition) return this.withOpacity(LunaUI.OPACITY_DISABLED);
|
||||
return this;
|
||||
}
|
||||
|
||||
Color enabled([bool condition = true]) {
|
||||
if (condition) return this;
|
||||
return this.withOpacity(LunaUI.OPACITY_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,14 @@ import 'package:lunasea/core.dart';
|
||||
// ignore: non_constant_identifier_names
|
||||
Decoration LunaCardDecoration({@required String uri, @required Map headers}) {
|
||||
if (LunaDatabaseValue.THEME_IMAGE_BACKGROUND_OPACITY.data == 0) return null;
|
||||
if (uri == null || uri.isEmpty)
|
||||
if (uri == null || uri.isEmpty) {
|
||||
return BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS));
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
);
|
||||
}
|
||||
|
||||
double _opacity =
|
||||
(LunaDatabaseValue.THEME_IMAGE_BACKGROUND_OPACITY.data as int) / 100;
|
||||
return BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: NetworkImage(
|
||||
@@ -15,12 +20,7 @@ Decoration LunaCardDecoration({@required String uri, @required Map headers}) {
|
||||
),
|
||||
// To prevent excessive logs, just handle an error loading the image with an empty callback
|
||||
onError: (error, stack) {},
|
||||
colorFilter: ColorFilter.mode(
|
||||
Colors.black.withOpacity(
|
||||
(LunaDatabaseValue.THEME_IMAGE_BACKGROUND_OPACITY.data as int) /
|
||||
100),
|
||||
BlendMode.dstATop,
|
||||
),
|
||||
opacity: _opacity,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
|
||||
@@ -4,10 +4,9 @@ import 'package:lunasea/core.dart';
|
||||
|
||||
// ignore: avoid_classes_with_only_static_members
|
||||
abstract class LunaDialog {
|
||||
static const HEADER_SIZE = LunaUI.FONT_SIZE_HEADER;
|
||||
static const BODY_SIZE = LunaUI.FONT_SIZE_SUBTITLE;
|
||||
static const SUBBODY_SIZE = LunaUI.FONT_SIZE_SUBHEADER;
|
||||
static const BUTTON_SIZE = LunaUI.FONT_SIZE_SUBHEADER;
|
||||
static const HEADER_SIZE = LunaUI.FONT_SIZE_H1;
|
||||
static const BODY_SIZE = LunaUI.FONT_SIZE_H3;
|
||||
static const BUTTON_SIZE = LunaUI.FONT_SIZE_H4;
|
||||
|
||||
static Widget title({
|
||||
@required String text,
|
||||
@@ -135,7 +134,7 @@ abstract class LunaDialog {
|
||||
decoration: InputDecoration(
|
||||
labelText: title,
|
||||
labelStyle: const TextStyle(
|
||||
color: Colors.white54,
|
||||
color: LunaColours.grey,
|
||||
decoration: TextDecoration.none,
|
||||
fontSize: LunaDialog.BODY_SIZE,
|
||||
),
|
||||
@@ -143,7 +142,8 @@ abstract class LunaDialog {
|
||||
borderSide: BorderSide(color: LunaColours.accent),
|
||||
),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: LunaColours.accent.withOpacity(0.3)),
|
||||
borderSide: BorderSide(
|
||||
color: LunaColours.accent.withOpacity(LunaUI.OPACITY_SPLASH)),
|
||||
),
|
||||
),
|
||||
style: const TextStyle(
|
||||
@@ -172,7 +172,7 @@ abstract class LunaDialog {
|
||||
decoration: InputDecoration(
|
||||
labelText: title,
|
||||
labelStyle: const TextStyle(
|
||||
color: Colors.white54,
|
||||
color: LunaColours.grey,
|
||||
decoration: TextDecoration.none,
|
||||
fontSize: LunaDialog.BODY_SIZE,
|
||||
),
|
||||
@@ -180,7 +180,8 @@ abstract class LunaDialog {
|
||||
borderSide: BorderSide(color: LunaColours.accent),
|
||||
),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: LunaColours.accent.withOpacity(0.3)),
|
||||
borderSide: BorderSide(
|
||||
color: LunaColours.accent.withOpacity(LunaUI.OPACITY_SPLASH)),
|
||||
),
|
||||
),
|
||||
style: const TextStyle(
|
||||
|
||||
@@ -31,12 +31,22 @@ class LunaDrawer extends StatelessWidget {
|
||||
valueListenable: Database.indexersBox.listenable(),
|
||||
builder: (context, indexerBox, widget) => Drawer(
|
||||
child: LunaDatabaseValue.DRAWER_AUTOMATIC_MANAGE.listen(
|
||||
builder: (context, _, __) => ListView(
|
||||
children: LunaDatabaseValue.DRAWER_AUTOMATIC_MANAGE.data
|
||||
? _getAlphabeticalOrder(context)
|
||||
: _getManualOrder(context),
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
physics: const ClampingScrollPhysics(),
|
||||
builder: (context, _, __) => Column(
|
||||
children: [
|
||||
LunaDrawerHeader(page: page),
|
||||
Expanded(
|
||||
child: LunaListView(
|
||||
controller: PrimaryScrollController.of(context),
|
||||
children: LunaDatabaseValue.DRAWER_AUTOMATIC_MANAGE.data
|
||||
? _getAlphabeticalOrder(context)
|
||||
: _getManualOrder(context),
|
||||
physics: const ClampingScrollPhysics(),
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).padding.bottom,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -46,12 +56,9 @@ class LunaDrawer extends StatelessWidget {
|
||||
|
||||
List<Widget> _sharedHeader(BuildContext context) {
|
||||
return [
|
||||
LunaDrawerHeader(),
|
||||
_buildEntry(context: context, module: LunaModule.DASHBOARD),
|
||||
_buildEntry(context: context, module: LunaModule.SETTINGS),
|
||||
const Divider(
|
||||
thickness: 1.0,
|
||||
color: Colors.white12,
|
||||
_buildEntry(
|
||||
context: context,
|
||||
module: LunaModule.DASHBOARD,
|
||||
),
|
||||
];
|
||||
}
|
||||
@@ -65,10 +72,10 @@ class LunaDrawer extends StatelessWidget {
|
||||
..._sharedHeader(context),
|
||||
..._modules.map((module) {
|
||||
if (module.isEnabled) {
|
||||
if (module == LunaModule.WAKE_ON_LAN) return _buildWakeOnLAN(context);
|
||||
return _buildEntry(
|
||||
context: context,
|
||||
module: module,
|
||||
onTap: module == LunaModule.WAKE_ON_LAN ? _wakeOnLAN : null,
|
||||
);
|
||||
}
|
||||
return const SizedBox(height: 0.0);
|
||||
@@ -82,10 +89,10 @@ class LunaDrawer extends StatelessWidget {
|
||||
..._sharedHeader(context),
|
||||
..._modules.map((module) {
|
||||
if (module.isEnabled) {
|
||||
if (module == LunaModule.WAKE_ON_LAN) return _buildWakeOnLAN(context);
|
||||
return _buildEntry(
|
||||
context: context,
|
||||
module: module,
|
||||
onTap: module == LunaModule.WAKE_ON_LAN ? _wakeOnLAN : null,
|
||||
);
|
||||
}
|
||||
return const SizedBox(height: 0.0);
|
||||
@@ -96,55 +103,54 @@ class LunaDrawer extends StatelessWidget {
|
||||
Widget _buildEntry({
|
||||
@required BuildContext context,
|
||||
@required LunaModule module,
|
||||
Function onTap,
|
||||
}) {
|
||||
bool currentPage = page == module.key.toLowerCase();
|
||||
return ListTile(
|
||||
leading: Icon(
|
||||
module.icon,
|
||||
color: currentPage ? module.color : Colors.white,
|
||||
),
|
||||
title: Text(
|
||||
module.name,
|
||||
style: TextStyle(
|
||||
color: currentPage ? module.color : Colors.white,
|
||||
fontSize: LunaUI.FONT_SIZE_SUBTITLE,
|
||||
return SizedBox(
|
||||
height: 56.0,
|
||||
child: InkWell(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
child: Icon(
|
||||
module.icon,
|
||||
color: currentPage ? module.color : LunaColours.white,
|
||||
),
|
||||
padding: LunaUI.MARGIN_DEFAULT_HORIZONTAL,
|
||||
),
|
||||
Text(
|
||||
module.name,
|
||||
style: TextStyle(
|
||||
color: currentPage ? module.color : LunaColours.white,
|
||||
fontWeight: LunaUI.FONT_WEIGHT_BOLD,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: onTap ??
|
||||
() async {
|
||||
Navigator.of(context).pop();
|
||||
if (!currentPage) module.launch();
|
||||
},
|
||||
),
|
||||
onTap: () async {
|
||||
Navigator.of(context).pop();
|
||||
if (!currentPage) module.launch();
|
||||
},
|
||||
contentPadding: const EdgeInsets.fromLTRB(16.0, 0.0, 0.0, 0.0),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildWakeOnLAN(BuildContext context) {
|
||||
return ListTile(
|
||||
leading: Icon(LunaModule.WAKE_ON_LAN.icon),
|
||||
title: Text(
|
||||
LunaModule.WAKE_ON_LAN.name,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: LunaUI.FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
),
|
||||
onTap: () async {
|
||||
WakeOnLANAPI api = WakeOnLANAPI.fromProfile();
|
||||
await api
|
||||
.wake()
|
||||
.then((_) => showLunaSuccessSnackBar(
|
||||
title: 'Machine is Waking Up...',
|
||||
message: 'Magic packet successfully sent',
|
||||
))
|
||||
.catchError((error, stack) {
|
||||
LunaLogger().error('Failed to wake machine', error, stack);
|
||||
return showLunaErrorSnackBar(
|
||||
title: 'Failed to Wake Machine',
|
||||
error: error,
|
||||
);
|
||||
});
|
||||
},
|
||||
contentPadding: const EdgeInsets.fromLTRB(16.0, 0.0, 0.0, 0.0),
|
||||
);
|
||||
Future<void> _wakeOnLAN() async {
|
||||
WakeOnLANAPI api = WakeOnLANAPI.fromProfile();
|
||||
await api
|
||||
.wake()
|
||||
.then((_) => showLunaSuccessSnackBar(
|
||||
title: 'Machine is Waking Up...',
|
||||
message: 'Magic packet successfully sent',
|
||||
))
|
||||
.catchError((error, stack) {
|
||||
LunaLogger().error('Failed to wake machine', error, stack);
|
||||
return showLunaErrorSnackBar(
|
||||
title: 'Failed to Wake Machine',
|
||||
error: error,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,72 +1,47 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LunaDrawerHeader extends UserAccountsDrawerHeader {
|
||||
LunaDrawerHeader({
|
||||
class LunaDrawerHeader extends StatelessWidget {
|
||||
final String page;
|
||||
|
||||
const LunaDrawerHeader({
|
||||
Key key,
|
||||
}) : super(
|
||||
key: key,
|
||||
accountName: StreamBuilder(
|
||||
stream: LunaFirebaseAuth.instance.authStateChanges(),
|
||||
builder: (context, snapshot) =>
|
||||
LunaText.title(text: LunaFirebaseAuth().email ?? 'LunaSea'),
|
||||
),
|
||||
accountEmail: LunaDatabaseValue.ENABLED_PROFILE.listen(
|
||||
builder: (context, lunaBox, widget) => ValueListenableBuilder(
|
||||
valueListenable: Database.profilesBox.listenable(),
|
||||
builder: (context, profilesBox, widget) => Padding(
|
||||
child: LunaPopupMenuButton<String>(
|
||||
tooltip: 'Change Profiles',
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
LunaText.subtitle(
|
||||
text: LunaDatabaseValue.ENABLED_PROFILE.data,
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_drop_down_rounded,
|
||||
color: Colors.white70,
|
||||
size: LunaUI.FONT_SIZE_HEADER,
|
||||
),
|
||||
],
|
||||
),
|
||||
onSelected: (result) {
|
||||
HapticFeedback.selectionClick();
|
||||
LunaProfile().safelyChangeProfiles(result);
|
||||
},
|
||||
itemBuilder: (context) {
|
||||
return <PopupMenuEntry<String>>[
|
||||
for (String profile in (profilesBox as Box).keys)
|
||||
PopupMenuItem<String>(
|
||||
value: profile,
|
||||
child: Text(
|
||||
profile,
|
||||
style: TextStyle(
|
||||
fontSize: LunaUI.FONT_SIZE_SUBTITLE,
|
||||
color: (LunaDatabaseValue.ENABLED_PROFILE.data ??
|
||||
'default') ==
|
||||
profile
|
||||
? LunaColours.accent
|
||||
: Colors.white,
|
||||
),
|
||||
),
|
||||
)
|
||||
];
|
||||
},
|
||||
),
|
||||
padding: const EdgeInsets.only(right: 12.0),
|
||||
),
|
||||
@required this.page,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LunaDatabaseValue.ENABLED_PROFILE.listen(
|
||||
builder: (context, box, _) => Container(
|
||||
child: LunaAppBar.dropdown(
|
||||
backgroundColor: Colors.transparent,
|
||||
hideLeading: true,
|
||||
useDrawer: false,
|
||||
title: Database.profilesBox.keys.length == 1
|
||||
? 'LunaSea'
|
||||
: Database.currentProfile ?? 'LunaSea',
|
||||
profiles: Database.profilesBox.keys.cast<String>().toList(),
|
||||
actions: [
|
||||
LunaIconButton(
|
||||
icon: LunaIcons.SETTINGS,
|
||||
onPressed: page == LunaModule.SETTINGS.key
|
||||
? Navigator.of(context).pop
|
||||
: LunaModule.SETTINGS.launch,
|
||||
)
|
||||
],
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: LunaColours.accent,
|
||||
image: DecorationImage(
|
||||
image: const AssetImage(LunaAssets.brandingLogo),
|
||||
colorFilter: ColorFilter.mode(
|
||||
LunaColours.primary.withOpacity(0.15),
|
||||
BlendMode.dstATop,
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: LunaColours.accent,
|
||||
image: DecorationImage(
|
||||
image: const AssetImage(LunaAssets.brandingLogo),
|
||||
colorFilter: ColorFilter.mode(
|
||||
LunaColours.primary.withOpacity(0.15), BlendMode.dstATop),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
);
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ class LunaFloatingActionButtonExtended extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
color: color,
|
||||
fontWeight: LunaUI.FONT_WEIGHT_BOLD,
|
||||
fontSize: LunaUI.FONT_SIZE_SUBTITLE,
|
||||
fontSize: LunaUI.FONT_SIZE_H3,
|
||||
letterSpacing: 0.35,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -4,13 +4,11 @@ import 'package:lunasea/core.dart';
|
||||
class LunaHeader extends StatelessWidget {
|
||||
final String text;
|
||||
final String subtitle;
|
||||
final EdgeInsets padding;
|
||||
|
||||
const LunaHeader({
|
||||
Key key,
|
||||
@required this.text,
|
||||
this.subtitle,
|
||||
this.padding,
|
||||
}) : super(key: key);
|
||||
|
||||
Widget _headerText() {
|
||||
@@ -18,7 +16,7 @@ class LunaHeader extends StatelessWidget {
|
||||
text.toUpperCase(),
|
||||
style: const TextStyle(
|
||||
fontWeight: LunaUI.FONT_WEIGHT_BOLD,
|
||||
fontSize: LunaUI.FONT_SIZE_HEADER,
|
||||
fontSize: LunaUI.FONT_SIZE_H2,
|
||||
color: Colors.white,
|
||||
),
|
||||
);
|
||||
@@ -28,28 +26,31 @@ class LunaHeader extends StatelessWidget {
|
||||
return Padding(
|
||||
child: Container(
|
||||
height: 2.0,
|
||||
width: 48.0,
|
||||
width: LunaUI.DEFAULT_MARGIN_SIZE * 3,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
color: LunaColours.accent,
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.only(
|
||||
top: 4.0,
|
||||
left: 1.0,
|
||||
bottom: subtitle != null ? 6.0 : 0.0,
|
||||
padding: const EdgeInsets.only(
|
||||
top: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
left: 0,
|
||||
bottom: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _subtitle() {
|
||||
return Text(
|
||||
subtitle,
|
||||
style: const TextStyle(
|
||||
fontSize: LunaUI.FONT_SIZE_SUBHEADER,
|
||||
color: Colors.white70,
|
||||
fontWeight: FontWeight.w300,
|
||||
return Padding(
|
||||
child: Text(
|
||||
subtitle,
|
||||
style: const TextStyle(
|
||||
fontSize: LunaUI.FONT_SIZE_H4,
|
||||
color: LunaColours.grey,
|
||||
fontWeight: FontWeight.w300,
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.only(bottom: LunaUI.DEFAULT_MARGIN_SIZE / 2),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -64,13 +65,11 @@ class LunaHeader extends StatelessWidget {
|
||||
if (subtitle != null) _subtitle(),
|
||||
],
|
||||
),
|
||||
padding: padding ??
|
||||
const EdgeInsets.fromLTRB(
|
||||
LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
LunaUI.DEFAULT_MARGIN_SIZE / 1.5,
|
||||
),
|
||||
padding: const EdgeInsets.only(
|
||||
left: LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
right: LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
top: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class LunaHighlightedNode extends StatelessWidget {
|
||||
text,
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
fontSize: LunaUI.FONT_SIZE_HIGHLIGHTED_NODE,
|
||||
fontSize: LunaUI.FONT_SIZE_H4,
|
||||
color: textColor,
|
||||
fontWeight: LunaUI.FONT_WEIGHT_BOLD,
|
||||
),
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export 'icons/icon_brands.dart';
|
||||
export 'icons/icon_button.dart';
|
||||
export 'icons/icon.dart';
|
||||
|
||||
30
lib/core/ui/icons/icon.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LunaIcons {
|
||||
static const IconData ADD = Icons.add_rounded;
|
||||
static const IconData ARROW_RIGHT = Icons.arrow_forward_ios_rounded;
|
||||
static const IconData ARROW_DROPDOWN = Icons.arrow_drop_down_rounded;
|
||||
static const IconData CLOUD_DELETE = Icons.cloud_off_rounded;
|
||||
static const IconData CLOUD_DOWNLOAD = Icons.cloud_download_rounded;
|
||||
static const IconData CLOUD_UPLOAD = Icons.cloud_upload_rounded;
|
||||
static const IconData CONNECTION_TEST = Icons.wifi_tethering_rounded;
|
||||
static const IconData DELETE = Icons.delete_rounded;
|
||||
static const IconData DEVICES = Icons.devices_rounded;
|
||||
static const IconData DOWNLOAD = Icons.file_download_rounded;
|
||||
static const IconData ERROR = Icons.error_rounded;
|
||||
static const IconData HOME = Icons.home_rounded;
|
||||
static const IconData MONITOR_OFF = Icons.turned_in_not_rounded;
|
||||
static const IconData MONITOR_ON = Icons.turned_in_rounded;
|
||||
static const IconData MUSIC = Icons.music_note_rounded;
|
||||
static const IconData PLAY = Icons.play_arrow_rounded;
|
||||
static const IconData PROFILES = Icons.switch_account_rounded;
|
||||
static const IconData REFRESH = Icons.refresh_rounded;
|
||||
static const IconData RENAME = Icons.text_format_rounded;
|
||||
static const IconData SEARCH = Icons.search_rounded;
|
||||
static const IconData SETTINGS = Icons.settings_rounded;
|
||||
static const IconData SHUFFLE = Icons.shuffle_rounded;
|
||||
static const IconData TRANSLATE = Icons.translate_rounded;
|
||||
static const IconData USER = Icons.person_rounded;
|
||||
static const IconData VIDEO_CAM = Icons.videocam_rounded;
|
||||
static const IconData WATCHED = Icons.visibility_rounded;
|
||||
}
|
||||
@@ -12,23 +12,49 @@ class LunaIconButton extends StatelessWidget {
|
||||
final Function onLongPress;
|
||||
final LunaLoadingState loadingState;
|
||||
final AlignmentGeometry alignment;
|
||||
final EdgeInsetsGeometry padding;
|
||||
final MouseCursor mouseCursor;
|
||||
|
||||
LunaIconButton({
|
||||
const LunaIconButton.arrow({
|
||||
Key key,
|
||||
this.text,
|
||||
this.textSize = 10.0,
|
||||
this.icon,
|
||||
this.iconSize = 24.0,
|
||||
this.textSize = LunaUI.FONT_SIZE_H5,
|
||||
this.icon = LunaIcons.ARROW_RIGHT,
|
||||
this.iconSize = LunaUI.ICON_SIZE,
|
||||
this.alignment = Alignment.center,
|
||||
this.padding = const EdgeInsets.all(8.0),
|
||||
this.color = Colors.white,
|
||||
this.onPressed,
|
||||
this.onLongPress,
|
||||
this.loadingState,
|
||||
}) : super(key: key) {
|
||||
assert((text != null || icon != null), 'both text and icon cannot be null');
|
||||
}
|
||||
this.mouseCursor,
|
||||
}) : super(key: key);
|
||||
|
||||
const LunaIconButton.appBar({
|
||||
Key key,
|
||||
this.text,
|
||||
this.textSize = LunaUI.FONT_SIZE_H5,
|
||||
this.icon,
|
||||
this.iconSize = LunaUI.ICON_SIZE,
|
||||
this.alignment = Alignment.center,
|
||||
this.color = Colors.white,
|
||||
this.onPressed,
|
||||
this.onLongPress,
|
||||
this.loadingState,
|
||||
this.mouseCursor,
|
||||
}) : super(key: key);
|
||||
|
||||
const LunaIconButton({
|
||||
Key key,
|
||||
this.text,
|
||||
this.textSize = LunaUI.FONT_SIZE_H5,
|
||||
this.icon,
|
||||
this.iconSize = LunaUI.ICON_SIZE,
|
||||
this.alignment = Alignment.center,
|
||||
this.color = Colors.white,
|
||||
this.onPressed,
|
||||
this.onLongPress,
|
||||
this.loadingState,
|
||||
this.mouseCursor,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -37,9 +63,14 @@ class LunaIconButton extends StatelessWidget {
|
||||
icon: loadingState == LunaLoadingState.ACTIVE ? _loader() : _icon(),
|
||||
iconSize: iconSize,
|
||||
alignment: alignment,
|
||||
padding: padding,
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: _onPressed(),
|
||||
mouseCursor: mouseCursor ??
|
||||
(onPressed != null ? SystemMouseCursors.click : MouseCursor.defer),
|
||||
),
|
||||
hoverColor: Colors.transparent,
|
||||
mouseCursor: mouseCursor ??
|
||||
(onLongPress != null ? SystemMouseCursors.click : MouseCursor.defer),
|
||||
onLongPress: _onLongPress(),
|
||||
);
|
||||
}
|
||||
@@ -64,13 +95,14 @@ class LunaIconButton extends StatelessWidget {
|
||||
|
||||
Widget _loader() {
|
||||
return LunaLoader(
|
||||
size: 12.0,
|
||||
size: LunaUI.FONT_SIZE_H4,
|
||||
color: color,
|
||||
useSafeArea: false,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _icon() {
|
||||
assert((text != null || icon != null), 'both text and icon cannot be null');
|
||||
if (loadingState == LunaLoadingState.ERROR) {
|
||||
return Icon(
|
||||
Icons.error_rounded,
|
||||
|
||||
@@ -2,13 +2,14 @@ import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LunaTextInputBar extends StatefulWidget {
|
||||
static const double appBarHeight = 62.0;
|
||||
static const double appBarInnerHeight = 62.0 - 13.0;
|
||||
static const double defaultHeight = 50.0;
|
||||
static const double defaultAppBarHeight =
|
||||
defaultHeight + LunaUI.DEFAULT_MARGIN_SIZE;
|
||||
static const EdgeInsets appBarMargin = EdgeInsets.fromLTRB(
|
||||
12.0,
|
||||
1.0,
|
||||
12.0,
|
||||
12.0,
|
||||
LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
0,
|
||||
LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
);
|
||||
|
||||
final TextEditingController controller;
|
||||
@@ -38,7 +39,7 @@ class LunaTextInputBar extends StatefulWidget {
|
||||
this.keyboardType = TextInputType.text,
|
||||
this.labelText,
|
||||
this.labelIcon = Icons.search_rounded,
|
||||
this.margin = LunaUI.MARGIN_CARD,
|
||||
this.margin = LunaUI.MARGIN_H_DEFAULT_V_HALF,
|
||||
this.autofocus = false,
|
||||
this.obscureText = false,
|
||||
this.isFormField = false,
|
||||
@@ -79,21 +80,21 @@ class _State extends State<LunaTextInputBar> {
|
||||
child: widget.isFormField ? _isForm : _isNotForm,
|
||||
),
|
||||
),
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
height: LunaTextInputBar.defaultHeight,
|
||||
color: Theme.of(context).canvasColor,
|
||||
);
|
||||
|
||||
TextStyle get _sharedTextStyle => const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: LunaUI.FONT_SIZE_SUBTITLE,
|
||||
color: LunaColours.white,
|
||||
fontSize: LunaUI.FONT_SIZE_H3,
|
||||
);
|
||||
|
||||
InputDecoration get _sharedInputDecoration => InputDecoration(
|
||||
labelText: widget.labelText ?? 'lunasea.SearchTextBar'.tr(),
|
||||
labelStyle: const TextStyle(
|
||||
color: Colors.white54,
|
||||
color: LunaColours.grey,
|
||||
decoration: TextDecoration.none,
|
||||
fontSize: LunaUI.FONT_SIZE_SUBTITLE,
|
||||
fontSize: LunaUI.FONT_SIZE_H3,
|
||||
),
|
||||
suffixIcon: AnimatedOpacity(
|
||||
child: InkWell(
|
||||
|
||||
35
lib/core/ui/linear_indicator.dart
Normal file
@@ -0,0 +1,35 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:percent_indicator/linear_percent_indicator.dart';
|
||||
|
||||
class LunaLinearPercentIndicator extends StatelessWidget {
|
||||
static const _LINE_HEIGHT = 4.0;
|
||||
static const double height = _LINE_HEIGHT + LunaUI.DEFAULT_MARGIN_SIZE / 2;
|
||||
|
||||
final double percent;
|
||||
final Color progressColor;
|
||||
final Color backgroundColor;
|
||||
|
||||
const LunaLinearPercentIndicator({
|
||||
Key key,
|
||||
this.percent,
|
||||
this.progressColor = LunaColours.accent,
|
||||
this.backgroundColor,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: height,
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: LinearPercentIndicator(
|
||||
percent: percent,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 2.0),
|
||||
lineHeight: 4.0,
|
||||
progressColor: progressColor,
|
||||
backgroundColor:
|
||||
backgroundColor ?? progressColor.withOpacity(LunaUI.OPACITY_SPLASH),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
export 'list_tile/expandable_list_tile.dart';
|
||||
export 'list_tile/list_tile.dart';
|
||||
|
||||
179
lib/core/ui/list_tile/expandable_list_tile.dart
Normal file
@@ -0,0 +1,179 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LunaExpandableListTile extends StatefulWidget {
|
||||
final String title;
|
||||
final List<TextSpan> collapsedSubtitles;
|
||||
final Widget collapsedTrailing;
|
||||
final Widget collapsedLeading;
|
||||
final Color backgroundColor;
|
||||
final Function onLongPress;
|
||||
final List<LunaHighlightedNode> expandedHighlightedNodes;
|
||||
final List<LunaTableContent> expandedTableContent;
|
||||
final List<LunaButton> expandedTableButtons;
|
||||
final bool initialExpanded;
|
||||
|
||||
/// Create a [LunaExpandableListTile] which is a list tile that expands into a table-style card.
|
||||
///
|
||||
/// If [expandedWidget] is supplied, that widget is used as the body within the expanded card.
|
||||
/// Any
|
||||
LunaExpandableListTile({
|
||||
Key key,
|
||||
@required this.title,
|
||||
@required this.collapsedSubtitles,
|
||||
@required this.expandedTableContent,
|
||||
this.collapsedTrailing,
|
||||
this.collapsedLeading,
|
||||
this.onLongPress,
|
||||
this.expandedHighlightedNodes,
|
||||
this.expandedTableButtons,
|
||||
this.backgroundColor,
|
||||
this.initialExpanded = false,
|
||||
}) : super(key: key) {
|
||||
assert(title != null);
|
||||
assert(collapsedSubtitles != null);
|
||||
assert(expandedTableContent != null);
|
||||
}
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<LunaExpandableListTile> {
|
||||
ExpandableController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
controller = ExpandableController(initialExpanded: widget.initialExpanded);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExpandableNotifier(
|
||||
controller: controller,
|
||||
child: Expandable(
|
||||
collapsed: collapsed(),
|
||||
expanded: expanded(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<TextSpan> _parseSubtitles() {
|
||||
if (widget.collapsedSubtitles.isEmpty) return [];
|
||||
List<TextSpan> _result = [];
|
||||
for (int i = 0; i < widget.collapsedSubtitles.length; i++) {
|
||||
_result.add(widget.collapsedSubtitles[i]);
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
Widget collapsed() {
|
||||
return LunaBlock(
|
||||
title: widget.title ?? LunaUI.TEXT_EMDASH,
|
||||
body: _parseSubtitles(),
|
||||
onTap: controller.toggle,
|
||||
onLongPress: widget.onLongPress,
|
||||
trailing: widget.collapsedTrailing,
|
||||
leading: widget.collapsedLeading,
|
||||
// color: widget.backgroundColor,
|
||||
);
|
||||
}
|
||||
|
||||
Widget expanded() {
|
||||
return LunaCard(
|
||||
context: context,
|
||||
child: InkWell(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
bottom: widget.expandedTableButtons?.isEmpty ?? true
|
||||
? (LunaUI.DEFAULT_MARGIN_SIZE / 4 * 3)
|
||||
: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
child: LunaText.title(
|
||||
text: widget.title ?? LunaUI.TEXT_EMDASH,
|
||||
softWrap: true,
|
||||
maxLines: 8,
|
||||
),
|
||||
padding: const EdgeInsets.only(
|
||||
left: LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
right: LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
bottom: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
),
|
||||
),
|
||||
if (widget.expandedHighlightedNodes != null)
|
||||
Padding(
|
||||
child: Wrap(
|
||||
direction: Axis.horizontal,
|
||||
spacing: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
runSpacing: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
children: widget.expandedHighlightedNodes,
|
||||
),
|
||||
padding: const EdgeInsets.only(
|
||||
left: LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
right: LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
bottom: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
),
|
||||
),
|
||||
...widget.expandedTableContent
|
||||
.map((child) => Padding(
|
||||
child: child,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
),
|
||||
))
|
||||
.toList(),
|
||||
if (widget.expandedTableButtons != null)
|
||||
Padding(
|
||||
child: Wrap(
|
||||
children: [
|
||||
...List.generate(
|
||||
widget.expandedTableButtons.length,
|
||||
(index) {
|
||||
int bCount = widget.expandedTableButtons.length;
|
||||
double widthFactor = 0.5;
|
||||
|
||||
if (index == (bCount - 1) && bCount.isOdd) {
|
||||
widthFactor = 1;
|
||||
}
|
||||
|
||||
return FractionallySizedBox(
|
||||
child: widget.expandedTableButtons[index],
|
||||
widthFactor: widthFactor,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
onTap: controller.toggle,
|
||||
onLongPress: widget.onLongPress,
|
||||
),
|
||||
color: widget.backgroundColor,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
@Deprecated("Use LunaBlock instead")
|
||||
class LunaListTile extends Card {
|
||||
LunaListTile({
|
||||
Key key,
|
||||
EdgeInsets margin = LunaUI.MARGIN_CARD,
|
||||
@required BuildContext context,
|
||||
@required Widget title,
|
||||
@required double height,
|
||||
Widget subtitle,
|
||||
Widget trailing,
|
||||
Widget leading,
|
||||
@@ -14,57 +15,65 @@ class LunaListTile extends Card {
|
||||
Decoration decoration,
|
||||
Function onTap,
|
||||
Function onLongPress,
|
||||
bool contentPadding = false,
|
||||
EdgeInsets customContentPadding,
|
||||
bool drawBorder = true,
|
||||
EdgeInsets margin = LunaUI.MARGIN_H_DEFAULT_V_HALF,
|
||||
}) : super(
|
||||
key: key,
|
||||
child: Container(
|
||||
height: height,
|
||||
child: InkWell(
|
||||
child: Row(
|
||||
children: [
|
||||
if (leading != null)
|
||||
SizedBox(
|
||||
width: LunaUI.DEFAULT_MARGIN_SIZE * 4 +
|
||||
LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
child: leading,
|
||||
),
|
||||
Expanded(
|
||||
child: ListTile(
|
||||
title: title,
|
||||
subtitle: subtitle,
|
||||
// trailing: trailing,
|
||||
leading: leading,
|
||||
mouseCursor: onTap != null || onLongPress != null
|
||||
? SystemMouseCursors.click
|
||||
: null,
|
||||
contentPadding: contentPadding
|
||||
? customContentPadding?.copyWith(
|
||||
right: trailing != null ? 0 : null,
|
||||
) ??
|
||||
LunaUI.MARGIN_CARD.copyWith(
|
||||
right: trailing != null ? 0 : null,
|
||||
)
|
||||
: LunaUI.MARGIN_CARD.copyWith(
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
right: trailing != null ? 0 : null,
|
||||
),
|
||||
child: Padding(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
child: title,
|
||||
height: LunaBlock.TITLE_HEIGHT,
|
||||
),
|
||||
if (subtitle != null) subtitle,
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.only(
|
||||
top: LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
bottom: LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
left: leading != null ? 0 : LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
right:
|
||||
trailing != null ? 0 : LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (trailing != null)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: LunaUI.MARGIN_CARD.right),
|
||||
padding: const EdgeInsets.only(
|
||||
right: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 48.0,
|
||||
width: LunaUI.DEFAULT_MARGIN_SIZE * 4,
|
||||
child: trailing,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
mouseCursor: SystemMouseCursors.click,
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
mouseCursor: MouseCursor.defer,
|
||||
),
|
||||
decoration: decoration,
|
||||
),
|
||||
margin: margin,
|
||||
elevation: LunaUI.ELEVATION,
|
||||
shape: LunaUI.shapeBorder,
|
||||
shape: drawBorder ? LunaUI.shapeBorder : LunaShapeBorder.rounded(),
|
||||
color: color ?? Theme.of(context).primaryColor,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,3 +5,4 @@ export 'list_view/list_view_modal_builder.dart';
|
||||
export 'list_view/paged_list_view.dart';
|
||||
export 'list_view/reorderable_list_view.dart';
|
||||
export 'list_view/reorderable_list_view_builder.dart';
|
||||
export 'list_view/reorderable_list_view_dragger.dart';
|
||||
|
||||
@@ -28,7 +28,7 @@ class LunaListView extends StatelessWidget {
|
||||
itemExtent: itemExtent,
|
||||
padding: padding ??
|
||||
MediaQuery.of(context).padding.add(EdgeInsets.symmetric(
|
||||
vertical: LunaUI.MARGIN_CARD.bottom,
|
||||
vertical: LunaUI.MARGIN_H_DEFAULT_V_HALF.bottom,
|
||||
)),
|
||||
physics: physics,
|
||||
),
|
||||
|
||||
@@ -31,7 +31,7 @@ class LunaListViewBuilder extends StatelessWidget {
|
||||
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
|
||||
padding: padding ??
|
||||
MediaQuery.of(context).padding.add(EdgeInsets.symmetric(
|
||||
vertical: LunaUI.MARGIN_CARD.bottom,
|
||||
vertical: LunaUI.MARGIN_H_DEFAULT_V_HALF.bottom,
|
||||
)),
|
||||
physics: physics,
|
||||
itemCount: itemCount,
|
||||
|
||||
@@ -53,12 +53,14 @@ class LunaListViewModal extends StatelessWidget {
|
||||
return EdgeInsets.fromLTRB(
|
||||
_padding.left + _viewInsets.left,
|
||||
appBar != null
|
||||
? LunaUI.MARGIN_CARD.top
|
||||
: _padding.top + _viewInsets.top + LunaUI.MARGIN_CARD.top,
|
||||
? LunaUI.MARGIN_H_DEFAULT_V_HALF.top
|
||||
: _padding.top + _viewInsets.top + LunaUI.MARGIN_H_DEFAULT_V_HALF.top,
|
||||
_padding.right + _viewInsets.right,
|
||||
actionBar != null
|
||||
? 0
|
||||
: _padding.bottom + _viewInsets.bottom + LunaUI.MARGIN_CARD.bottom,
|
||||
: _padding.bottom +
|
||||
_viewInsets.bottom +
|
||||
LunaUI.MARGIN_H_DEFAULT_V_HALF.bottom,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,12 +66,14 @@ class LunaListViewModalBuilder extends StatelessWidget {
|
||||
return EdgeInsets.fromLTRB(
|
||||
_padding.left + _viewInsets.left,
|
||||
appBar != null
|
||||
? LunaUI.MARGIN_CARD.top
|
||||
: _padding.top + _viewInsets.top + LunaUI.MARGIN_CARD.top,
|
||||
? LunaUI.MARGIN_H_DEFAULT_V_HALF.top
|
||||
: _padding.top + _viewInsets.top + LunaUI.MARGIN_H_DEFAULT_V_HALF.top,
|
||||
_padding.right + _viewInsets.right,
|
||||
actionBar != null
|
||||
? 0
|
||||
: _padding.bottom + _viewInsets.bottom + LunaUI.MARGIN_CARD.bottom,
|
||||
: _padding.bottom +
|
||||
_viewInsets.bottom +
|
||||
LunaUI.MARGIN_H_DEFAULT_V_HALF.bottom,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,11 +68,11 @@ class _State<T> extends State<LunaPagedListView<T>> {
|
||||
),
|
||||
padding: const EdgeInsets.only(bottom: 0.0),
|
||||
),
|
||||
newPageErrorIndicatorBuilder: (context) => LunaIconButton(
|
||||
newPageErrorIndicatorBuilder: (context) => const LunaIconButton(
|
||||
icon: Icons.error_rounded,
|
||||
color: LunaColours.red,
|
||||
),
|
||||
noMoreItemsIndicatorBuilder: (context) => LunaIconButton(
|
||||
noMoreItemsIndicatorBuilder: (context) => const LunaIconButton(
|
||||
icon: Icons.check_rounded,
|
||||
color: LunaColours.accent,
|
||||
),
|
||||
@@ -85,8 +85,9 @@ class _State<T> extends State<LunaPagedListView<T>> {
|
||||
padding: widget.padding ??
|
||||
MediaQuery.of(context)
|
||||
.padding
|
||||
.copyWith(bottom: LunaUI.MARGIN_CARD.bottom)
|
||||
.add(EdgeInsets.only(top: LunaUI.MARGIN_CARD.top)),
|
||||
.copyWith(bottom: LunaUI.MARGIN_H_DEFAULT_V_HALF.bottom)
|
||||
.add(
|
||||
EdgeInsets.only(top: LunaUI.MARGIN_H_DEFAULT_V_HALF.top)),
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -30,7 +30,7 @@ class LunaReorderableListView extends StatelessWidget {
|
||||
children: children,
|
||||
padding: padding ??
|
||||
MediaQuery.of(context).padding.add(EdgeInsets.symmetric(
|
||||
vertical: LunaUI.MARGIN_CARD.bottom,
|
||||
vertical: LunaUI.MARGIN_H_DEFAULT_V_HALF.bottom,
|
||||
)),
|
||||
physics: physics,
|
||||
onReorder: onReorder,
|
||||
|
||||
@@ -34,7 +34,7 @@ class LunaReorderableListViewBuilder extends StatelessWidget {
|
||||
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
|
||||
padding: padding ??
|
||||
MediaQuery.of(context).padding.add(EdgeInsets.symmetric(
|
||||
vertical: LunaUI.MARGIN_CARD.bottom,
|
||||
vertical: LunaUI.MARGIN_H_DEFAULT_V_HALF.bottom,
|
||||
)),
|
||||
physics: physics,
|
||||
itemCount: itemCount,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LunaReorderableListDragger extends StatelessWidget {
|
||||
class LunaReorderableListViewDragger extends StatelessWidget {
|
||||
final int index;
|
||||
|
||||
const LunaReorderableListDragger({
|
||||
const LunaReorderableListViewDragger({
|
||||
Key key,
|
||||
@required this.index,
|
||||
}) : super(key: key);
|
||||
@@ -15,7 +16,10 @@ class LunaReorderableListDragger extends StatelessWidget {
|
||||
children: [
|
||||
ReorderableDragStartListener(
|
||||
index: index,
|
||||
child: const Icon(Icons.menu_rounded),
|
||||
child: const LunaIconButton(
|
||||
icon: Icons.menu_rounded,
|
||||
mouseCursor: SystemMouseCursors.click,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -98,7 +98,7 @@ class LunaMessage extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Card(
|
||||
margin: LunaUI.MARGIN_CARD,
|
||||
margin: LunaUI.MARGIN_H_DEFAULT_V_HALF,
|
||||
elevation: LunaUI.ELEVATION,
|
||||
shape: LunaUI.shapeBorder,
|
||||
child: Row(
|
||||
|
||||
@@ -1,37 +1,57 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:transparent_image/transparent_image.dart';
|
||||
|
||||
class LunaNetworkImage extends ClipRRect {
|
||||
LunaNetworkImage({
|
||||
Key key,
|
||||
double height,
|
||||
double width,
|
||||
@required BuildContext context,
|
||||
@required double height,
|
||||
@required double width,
|
||||
String url,
|
||||
@required String placeholderAsset,
|
||||
IconData placeholderIcon,
|
||||
@Deprecated('Use placeholderIcon') String placeholderAsset,
|
||||
Map headers,
|
||||
bool roundCorners = true,
|
||||
}) : super(
|
||||
key: key,
|
||||
child: SizedBox(
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
placeholderAsset,
|
||||
Container(
|
||||
height: height,
|
||||
width: width,
|
||||
child: Center(
|
||||
child: placeholderIcon != null
|
||||
? Icon(
|
||||
placeholderIcon,
|
||||
color: LunaColours.accent,
|
||||
size: height / 3,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).canvasColor,
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
border: LunaUI.shouldUseBorder
|
||||
? Border.all(color: LunaColours.white10)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
if (url != null && url.isNotEmpty)
|
||||
if (url?.isNotEmpty ?? false)
|
||||
FadeInImage(
|
||||
height: height,
|
||||
width: width,
|
||||
fadeInDuration: const Duration(
|
||||
milliseconds: LunaUI.ANIMATION_IMAGE_FADE_IN_SPEED),
|
||||
milliseconds: LunaUI.ANIMATION_SPEED_IMAGES,
|
||||
),
|
||||
fadeOutDuration: const Duration(milliseconds: 1),
|
||||
placeholder: AssetImage(placeholderAsset),
|
||||
placeholder: MemoryImage(kTransparentImage),
|
||||
fit: BoxFit.cover,
|
||||
image: NetworkImage(url,
|
||||
headers: headers?.cast<String, String>()),
|
||||
image: NetworkImage(
|
||||
url,
|
||||
headers: headers?.cast<String, String>(),
|
||||
),
|
||||
imageErrorBuilder: (context, error, stack) => SizedBox(
|
||||
height: height,
|
||||
width: width,
|
||||
@@ -42,11 +62,7 @@ class LunaNetworkImage extends ClipRRect {
|
||||
height: height,
|
||||
width: width,
|
||||
),
|
||||
borderRadius:
|
||||
roundCorners ? BorderRadius.circular(LunaUI.BORDER_RADIUS) : null,
|
||||
) {
|
||||
// assert(height != null);
|
||||
// assert(width != null);
|
||||
assert(placeholderAsset != null);
|
||||
}
|
||||
clipBehavior: Clip.antiAlias,
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@ class LunaShapeBorder extends RoundedRectangleBorder {
|
||||
bool useBorder = false,
|
||||
}) : super(
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
side: useBorder ? const BorderSide(color: Colors.white12) : BorderSide.none,
|
||||
side: useBorder
|
||||
? const BorderSide(color: LunaColours.white10)
|
||||
: BorderSide.none,
|
||||
);
|
||||
|
||||
factory LunaShapeBorder.rounded() => LunaShapeBorder._internal();
|
||||
|
||||
@@ -36,8 +36,6 @@ extension LunaSnackbarTypeExtension on LunaSnackbarType {
|
||||
}
|
||||
}
|
||||
|
||||
const _PADDING = 8.0;
|
||||
|
||||
Future<void> showLunaSnackBar({
|
||||
@required String title,
|
||||
@required LunaSnackbarType type,
|
||||
@@ -56,31 +54,28 @@ Future<void> showLunaSnackBar({
|
||||
controller: controller,
|
||||
boxShadows: [
|
||||
BoxShadow(
|
||||
blurRadius: 6.0,
|
||||
spreadRadius: 4.0,
|
||||
color: Colors.black.withOpacity(0.10))
|
||||
blurRadius: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
spreadRadius: LunaUI.DEFAULT_MARGIN_SIZE / 4,
|
||||
color: Colors.black.withOpacity(LunaUI.OPACITY_SPLASH / 2),
|
||||
),
|
||||
],
|
||||
horizontalDismissDirection: HorizontalDismissDirection.horizontal,
|
||||
margin: const EdgeInsets.all(_PADDING),
|
||||
margin: LunaUI.MARGIN_DEFAULT,
|
||||
behavior: FlashBehavior.floating,
|
||||
position: position,
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
borderColor:
|
||||
LunaUI.shouldUseBorder ? Colors.white12 : Colors.transparent,
|
||||
LunaUI.shouldUseBorder ? LunaColours.white10 : Colors.transparent,
|
||||
child: FlashBar(
|
||||
title: Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontWeight: LunaUI.FONT_WEIGHT_BOLD,
|
||||
fontSize: LunaUI.FONT_SIZE_TITLE,
|
||||
),
|
||||
title: LunaText.title(
|
||||
text: title,
|
||||
maxLines: 4,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
content: Text(
|
||||
message,
|
||||
style: const TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: LunaUI.FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
content: LunaText.subtitle(
|
||||
text: message,
|
||||
maxLines: 8,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
shouldIconPulse: false,
|
||||
icon: Padding(
|
||||
@@ -88,7 +83,9 @@ Future<void> showLunaSnackBar({
|
||||
icon: type.icon,
|
||||
color: type.color,
|
||||
),
|
||||
padding: const EdgeInsets.only(left: _PADDING),
|
||||
padding: const EdgeInsets.only(
|
||||
left: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
),
|
||||
),
|
||||
primaryAction: showButton
|
||||
? TextButton(
|
||||
|
||||
@@ -19,9 +19,14 @@ class LunaTableCard extends StatelessWidget {
|
||||
context: context,
|
||||
child: Padding(
|
||||
child: _body(),
|
||||
padding: buttons == null
|
||||
? const EdgeInsets.symmetric(vertical: 8.0)
|
||||
: const EdgeInsets.only(top: 8.0, bottom: 6.0),
|
||||
padding: EdgeInsets.only(
|
||||
left: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
right: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
top: LunaUI.DEFAULT_MARGIN_SIZE - LunaUI.DEFAULT_MARGIN_SIZE / 4,
|
||||
bottom: buttons?.isEmpty ?? true
|
||||
? LunaUI.DEFAULT_MARGIN_SIZE - LunaUI.DEFAULT_MARGIN_SIZE / 4
|
||||
: 0,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -40,7 +45,8 @@ class LunaTableCard extends StatelessWidget {
|
||||
return Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: LunaUI.DEFAULT_MARGIN_SIZE),
|
||||
child: LunaText.title(text: title),
|
||||
),
|
||||
],
|
||||
@@ -49,12 +55,13 @@ class LunaTableCard extends StatelessWidget {
|
||||
|
||||
List<Widget> _content() {
|
||||
return content
|
||||
?.map<Widget>((content) => Padding(
|
||||
child: content,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
))
|
||||
?.toList() ??
|
||||
[];
|
||||
.map((child) => Padding(
|
||||
child: child,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
),
|
||||
))
|
||||
.toList();
|
||||
}
|
||||
|
||||
Widget _buttons() {
|
||||
@@ -64,7 +71,10 @@ class LunaTableCard extends StatelessWidget {
|
||||
children:
|
||||
buttons.map<Widget>((button) => Expanded(child: button)).toList(),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6.0),
|
||||
padding: const EdgeInsets.only(
|
||||
top: LunaUI.DEFAULT_MARGIN_SIZE / 2 - LunaUI.DEFAULT_MARGIN_SIZE / 4,
|
||||
bottom: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,56 +1,94 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
enum _Type {
|
||||
CONTENT,
|
||||
SPACER,
|
||||
}
|
||||
|
||||
class LunaTableContent extends StatelessWidget {
|
||||
final String title;
|
||||
final String body;
|
||||
final bool bodyIsUrl;
|
||||
final int titleFlex;
|
||||
final int bodyFlex;
|
||||
final double spacerSize;
|
||||
final TextAlign titleAlign;
|
||||
final TextAlign bodyAlign;
|
||||
final Color titleColor;
|
||||
final Color bodyColor;
|
||||
final EdgeInsets padding;
|
||||
final _Type type;
|
||||
|
||||
const LunaTableContent({
|
||||
const LunaTableContent._({
|
||||
Key key,
|
||||
@required this.title,
|
||||
@required this.body,
|
||||
this.title,
|
||||
this.body,
|
||||
this.bodyIsUrl = false,
|
||||
this.titleAlign = TextAlign.end,
|
||||
this.bodyAlign = TextAlign.start,
|
||||
this.titleFlex = 5,
|
||||
this.bodyFlex = 10,
|
||||
this.titleColor = Colors.white70,
|
||||
this.bodyColor = Colors.white,
|
||||
this.padding = const EdgeInsets.symmetric(vertical: 4.0),
|
||||
}) : super(key: key);
|
||||
this.spacerSize = LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
@required this.type,
|
||||
});
|
||||
|
||||
factory LunaTableContent.spacer({
|
||||
Key key,
|
||||
double spacerSize = LunaUI.DEFAULT_MARGIN_SIZE,
|
||||
}) =>
|
||||
LunaTableContent._(
|
||||
key: key,
|
||||
type: _Type.SPACER,
|
||||
spacerSize: spacerSize,
|
||||
);
|
||||
|
||||
factory LunaTableContent({
|
||||
Key key,
|
||||
@required String title,
|
||||
@required String body,
|
||||
bool bodyIsUrl = false,
|
||||
TextAlign titleAlign = TextAlign.end,
|
||||
TextAlign bodyAlign = TextAlign.start,
|
||||
int titleFlex = 1,
|
||||
int bodyFlex = 2,
|
||||
}) =>
|
||||
LunaTableContent._(
|
||||
key: key,
|
||||
title: title,
|
||||
body: body,
|
||||
bodyIsUrl: bodyIsUrl,
|
||||
titleAlign: titleAlign,
|
||||
bodyAlign: bodyAlign,
|
||||
titleFlex: titleFlex,
|
||||
bodyFlex: bodyFlex,
|
||||
type: _Type.CONTENT,
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
child: Row(
|
||||
children: [
|
||||
_title(),
|
||||
SizedBox(width: LunaUI.MARGIN_DEFAULT.left, height: 0.0),
|
||||
_subtitle(),
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
),
|
||||
padding: padding,
|
||||
if (type == _Type.SPACER) return SizedBox(height: spacerSize);
|
||||
return Row(
|
||||
children: [
|
||||
_title(),
|
||||
_subtitle(),
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _title() {
|
||||
return Expanded(
|
||||
child: Text(
|
||||
title?.toUpperCase() ?? LunaUI.TEXT_EMDASH,
|
||||
textAlign: titleAlign,
|
||||
style: TextStyle(
|
||||
color: titleColor,
|
||||
fontSize: LunaUI.FONT_SIZE_SUBTITLE,
|
||||
child: Padding(
|
||||
child: Text(
|
||||
title?.toUpperCase() ?? LunaUI.TEXT_EMDASH,
|
||||
textAlign: titleAlign,
|
||||
style: const TextStyle(
|
||||
color: LunaColours.grey,
|
||||
fontSize: LunaUI.FONT_SIZE_H3,
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.only(
|
||||
top: LunaUI.DEFAULT_MARGIN_SIZE / 4,
|
||||
bottom: LunaUI.DEFAULT_MARGIN_SIZE / 4,
|
||||
right: LunaUI.DEFAULT_MARGIN_SIZE / 4,
|
||||
),
|
||||
),
|
||||
flex: titleFlex,
|
||||
@@ -60,24 +98,24 @@ class LunaTableContent extends StatelessWidget {
|
||||
Widget _subtitle() {
|
||||
return Expanded(
|
||||
child: InkWell(
|
||||
child: Text(
|
||||
body ?? LunaUI.TEXT_EMDASH,
|
||||
textAlign: bodyAlign,
|
||||
style: TextStyle(
|
||||
color: bodyColor,
|
||||
fontSize: LunaUI.FONT_SIZE_SUBTITLE,
|
||||
child: Padding(
|
||||
child: Text(
|
||||
body ?? LunaUI.TEXT_EMDASH,
|
||||
textAlign: bodyAlign,
|
||||
style: const TextStyle(
|
||||
color: LunaColours.white,
|
||||
fontSize: LunaUI.FONT_SIZE_H3,
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.only(
|
||||
top: LunaUI.DEFAULT_MARGIN_SIZE / 4,
|
||||
bottom: LunaUI.DEFAULT_MARGIN_SIZE / 4,
|
||||
left: LunaUI.DEFAULT_MARGIN_SIZE / 2,
|
||||
),
|
||||
),
|
||||
onTap: !bodyIsUrl ? null : body.lunaOpenGenericLink,
|
||||
onLongPress: !bodyIsUrl
|
||||
? null
|
||||
: () async {
|
||||
await Clipboard.setData(ClipboardData(text: body));
|
||||
showLunaSuccessSnackBar(
|
||||
title: 'Copied Content',
|
||||
message: 'Copied link to the clipboard');
|
||||
},
|
||||
borderRadius: BorderRadius.circular(5.0),
|
||||
onLongPress: !bodyIsUrl ? null : () => body.copyToClipboard(),
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
),
|
||||
flex: bodyFlex,
|
||||
);
|
||||
|
||||
@@ -27,21 +27,22 @@ class LunaText extends Text {
|
||||
@required String text,
|
||||
int maxLines = 1,
|
||||
bool softWrap = false,
|
||||
@Deprecated('Dead property') bool darken,
|
||||
TextAlign textAlign = TextAlign.start,
|
||||
TextOverflow overflow = TextOverflow.fade,
|
||||
Color color = Colors.white,
|
||||
bool darken = false,
|
||||
}) =>
|
||||
LunaText(
|
||||
text: text,
|
||||
key: key,
|
||||
maxLines: maxLines,
|
||||
overflow: TextOverflow.fade,
|
||||
overflow: overflow,
|
||||
softWrap: softWrap,
|
||||
textAlign: textAlign,
|
||||
style: TextStyle(
|
||||
color: darken ? color.withOpacity(0.30) : color,
|
||||
color: color,
|
||||
fontWeight: LunaUI.FONT_WEIGHT_BOLD,
|
||||
fontSize: LunaUI.FONT_SIZE_TITLE,
|
||||
fontSize: LunaUI.FONT_SIZE_H2,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -51,9 +52,10 @@ class LunaText extends Text {
|
||||
@required String text,
|
||||
int maxLines = 1,
|
||||
bool softWrap = false,
|
||||
@Deprecated('Dead property') bool darken,
|
||||
TextAlign textAlign = TextAlign.start,
|
||||
Color color = Colors.white70,
|
||||
bool darken = false,
|
||||
TextOverflow overflow = TextOverflow.fade,
|
||||
Color color = LunaColours.grey,
|
||||
FontStyle fontStyle = FontStyle.normal,
|
||||
}) =>
|
||||
LunaText(
|
||||
@@ -62,10 +64,10 @@ class LunaText extends Text {
|
||||
softWrap: softWrap,
|
||||
maxLines: maxLines,
|
||||
textAlign: textAlign,
|
||||
overflow: TextOverflow.fade,
|
||||
overflow: overflow,
|
||||
style: TextStyle(
|
||||
color: darken ? color.withOpacity(0.30) : color,
|
||||
fontSize: LunaUI.FONT_SIZE_SUBTITLE,
|
||||
color: color,
|
||||
fontSize: LunaUI.FONT_SIZE_H3,
|
||||
fontStyle: fontStyle,
|
||||
),
|
||||
);
|
||||
|
||||
13
lib/core/ui/text_span.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LunaTextSpan extends TextSpan {
|
||||
const LunaTextSpan.extended({
|
||||
@required String text,
|
||||
}) : super(
|
||||
text: text,
|
||||
style: const TextStyle(
|
||||
height: LunaBlock.SUBTITLE_HEIGHT / LunaUI.FONT_SIZE_H3,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -35,10 +35,10 @@ class LunaTheme {
|
||||
brightness: Brightness.dark,
|
||||
canvasColor: LunaColours.primary,
|
||||
primaryColor: LunaColours.secondary,
|
||||
highlightColor: LunaColours.splash.withOpacity(0.15),
|
||||
highlightColor: LunaColours.splash.withOpacity(LunaUI.OPACITY_SPLASH / 2),
|
||||
cardColor: LunaColours.secondary,
|
||||
hoverColor: LunaColours.accent.withOpacity(0.15),
|
||||
splashColor: LunaColours.accent.withOpacity(0.30),
|
||||
hoverColor: LunaColours.accent.withOpacity(LunaUI.OPACITY_SPLASH / 2),
|
||||
splashColor: LunaColours.accent.withOpacity(LunaUI.OPACITY_SPLASH),
|
||||
dialogBackgroundColor: LunaColours.secondary,
|
||||
toggleableActiveColor: LunaColours.accent,
|
||||
iconTheme: const IconThemeData(
|
||||
@@ -50,7 +50,7 @@ class LunaTheme {
|
||||
borderRadius: BorderRadius.all(Radius.circular(LunaUI.BORDER_RADIUS)),
|
||||
),
|
||||
textStyle: TextStyle(
|
||||
color: Colors.white70,
|
||||
color: LunaColours.grey,
|
||||
fontSize: LunaUI.FONT_SIZE_SUBHEADER,
|
||||
),
|
||||
preferBelow: true,
|
||||
@@ -68,10 +68,10 @@ class LunaTheme {
|
||||
brightness: Brightness.dark,
|
||||
canvasColor: Colors.black,
|
||||
primaryColor: Colors.black,
|
||||
highlightColor: LunaColours.splash.withOpacity(0.15),
|
||||
highlightColor: LunaColours.splash.withOpacity(LunaUI.OPACITY_SPLASH / 2),
|
||||
cardColor: Colors.black,
|
||||
hoverColor: LunaColours.accent.withOpacity(0.15),
|
||||
splashColor: LunaColours.accent.withOpacity(0.30),
|
||||
hoverColor: LunaColours.accent.withOpacity(LunaUI.OPACITY_SPLASH / 2),
|
||||
splashColor: LunaColours.accent.withOpacity(LunaUI.OPACITY_SPLASH),
|
||||
dialogBackgroundColor: Colors.black,
|
||||
toggleableActiveColor: LunaColours.accent,
|
||||
iconTheme: const IconThemeData(
|
||||
@@ -83,10 +83,11 @@ class LunaTheme {
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(LunaUI.BORDER_RADIUS),
|
||||
),
|
||||
border: useAMOLEDBorders ? Border.all(color: Colors.white12) : null,
|
||||
border:
|
||||
useAMOLEDBorders ? Border.all(color: LunaColours.white10) : null,
|
||||
),
|
||||
textStyle: const TextStyle(
|
||||
color: Colors.white70,
|
||||
color: LunaColours.grey,
|
||||
fontSize: LunaUI.FONT_SIZE_SUBHEADER,
|
||||
),
|
||||
preferBelow: true,
|
||||
@@ -121,7 +122,7 @@ class LunaTheme {
|
||||
return TextButtonThemeData(
|
||||
style: ButtonStyle(
|
||||
overlayColor: MaterialStateProperty.all<Color>(
|
||||
LunaColours.splash.withOpacity(0.30),
|
||||
LunaColours.splash.withOpacity(LunaUI.OPACITY_SPLASH),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -4,123 +4,141 @@ import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
class LunaChangelog {
|
||||
/// Check if the current build number is not equal to the stored build number.
|
||||
///
|
||||
/// If they are not the same, stores the current build number and shows the changelog.
|
||||
Future<void> checkAndShowChangelog() async {
|
||||
PackageInfo.fromPlatform().then((package) {
|
||||
if (package != null &&
|
||||
AlertsDatabaseValue.CHANGELOG.data != package.buildNumber) {
|
||||
AlertsDatabaseValue.CHANGELOG.put(package.buildNumber);
|
||||
showChangelog(package.version, package.buildNumber);
|
||||
}
|
||||
}).catchError((error, stack) {
|
||||
LunaLogger().error('Failed to fetch platform information', error, stack);
|
||||
});
|
||||
class LunaChangelogSheet extends LunaBottomModalSheet {
|
||||
_Changelog _changelog;
|
||||
String _version;
|
||||
String _buildNumber;
|
||||
|
||||
static Future<dynamic> delayedShow([
|
||||
Duration duration = const Duration(seconds: 1),
|
||||
bool checkBuildNumber = true,
|
||||
]) async {
|
||||
Future.delayed(
|
||||
duration,
|
||||
() async => LunaChangelogSheet().show(
|
||||
context: LunaState.navigatorKey.currentContext,
|
||||
checkBuildNumber: checkBuildNumber,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Load the changelog asset and show a bottom modal sheet with the changelog.
|
||||
Future<void> showChangelog(String version, String buildNumber) async {
|
||||
await DefaultAssetBundle.of(LunaState.navigatorKey.currentContext)
|
||||
.loadString('assets/changelog.json')
|
||||
.then((data) {
|
||||
_Changelog changelog = _Changelog.fromJson(json.decode(data));
|
||||
// TODO: Abstract this
|
||||
LunaBottomModalSheet().showModal(
|
||||
context: LunaState.navigatorKey.currentContext,
|
||||
builder: (context) => LunaListViewModal(
|
||||
children: [
|
||||
if (version != null && buildNumber != null)
|
||||
LunaHeader(
|
||||
text: '$version ($buildNumber)', subtitle: changelog.motd),
|
||||
if (version == null || buildNumber == null)
|
||||
LunaHeader(text: 'LunaSea', subtitle: changelog.motd),
|
||||
if ((changelog.changesNew?.length ?? 0) != 0)
|
||||
const LunaHeader(text: 'New'),
|
||||
if ((changelog.changesNew?.length ?? 0) != 0)
|
||||
LunaTableCard(
|
||||
content: List<LunaTableContent>.generate(
|
||||
changelog.changesNew.length,
|
||||
(index) => LunaTableContent(
|
||||
title: changelog.changesNew[index].module,
|
||||
body: changelog.changesNew[index].changes
|
||||
.fold(
|
||||
'',
|
||||
(data, object) =>
|
||||
data += '${LunaUI.TEXT_BULLET}\t$object\n')
|
||||
.trim(),
|
||||
),
|
||||
),
|
||||
),
|
||||
if ((changelog.changesTweaks?.length ?? 0) != 0)
|
||||
const LunaHeader(text: 'Tweaks'),
|
||||
if ((changelog.changesTweaks?.length ?? 0) != 0)
|
||||
LunaTableCard(
|
||||
content: List<LunaTableContent>.generate(
|
||||
changelog.changesTweaks.length,
|
||||
(index) => LunaTableContent(
|
||||
title: changelog.changesTweaks[index].module,
|
||||
body: changelog.changesTweaks[index].changes
|
||||
.fold(
|
||||
'',
|
||||
(data, object) =>
|
||||
data += '${LunaUI.TEXT_BULLET}\t$object\n')
|
||||
.trim(),
|
||||
),
|
||||
),
|
||||
),
|
||||
if ((changelog.changesFixes?.length ?? 0) != 0)
|
||||
const LunaHeader(text: 'Fixes'),
|
||||
if ((changelog.changesFixes?.length ?? 0) != 0)
|
||||
LunaTableCard(
|
||||
content: List<LunaTableContent>.generate(
|
||||
changelog.changesFixes.length,
|
||||
(index) => LunaTableContent(
|
||||
title: changelog.changesFixes[index].module,
|
||||
body: changelog.changesFixes[index].changes
|
||||
.fold(
|
||||
'',
|
||||
(data, object) =>
|
||||
data += '${LunaUI.TEXT_BULLET}\t$object\n')
|
||||
.trim(),
|
||||
),
|
||||
),
|
||||
),
|
||||
if ((changelog.changesPlatform?.length ?? 0) != 0)
|
||||
const LunaHeader(text: 'Platform-Specific'),
|
||||
if ((changelog.changesPlatform?.length ?? 0) != 0)
|
||||
LunaTableCard(
|
||||
content: List<LunaTableContent>.generate(
|
||||
changelog.changesPlatform.length,
|
||||
(index) => LunaTableContent(
|
||||
title: changelog.changesPlatform[index].module,
|
||||
body: changelog.changesPlatform[index].changes
|
||||
.fold(
|
||||
'',
|
||||
(data, object) =>
|
||||
data += '${LunaUI.TEXT_BULLET}\t$object\n')
|
||||
.trim(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: LunaUI.DEFAULT_MARGIN_SIZE / 2),
|
||||
],
|
||||
actionBar: LunaBottomActionBar(
|
||||
actions: [
|
||||
LunaButton.text(
|
||||
text: 'Full Changelog',
|
||||
icon: Icons.track_changes_rounded,
|
||||
onTap: LunaLinks.CHANGELOG.launch,
|
||||
),
|
||||
],
|
||||
@override
|
||||
Future<dynamic> show({
|
||||
@required BuildContext context,
|
||||
Widget Function(BuildContext context) builder,
|
||||
bool checkBuildNumber = false,
|
||||
}) async {
|
||||
try {
|
||||
_changelog =
|
||||
await DefaultAssetBundle.of(LunaState.navigatorKey.currentContext)
|
||||
.loadString('assets/changelog.json')
|
||||
.then((data) => _Changelog.fromJson(json.decode(data)));
|
||||
|
||||
PackageInfo _package = await PackageInfo.fromPlatform();
|
||||
if (_package == null) return;
|
||||
|
||||
_version = _package.version;
|
||||
_buildNumber = _package.buildNumber;
|
||||
|
||||
if (checkBuildNumber) {
|
||||
AlertsDatabaseValue _db = AlertsDatabaseValue.CHANGELOG;
|
||||
if (_db.data == _package.buildNumber) return;
|
||||
_db.put(_package.buildNumber);
|
||||
}
|
||||
|
||||
return this.showModal(context: context, builder: builder);
|
||||
} catch (error, stack) {
|
||||
LunaLogger().error('Failed to show changelog sheet', error, stack);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget builder(BuildContext context) {
|
||||
return LunaListViewModal(
|
||||
children: [
|
||||
if (_version != null && _buildNumber != null)
|
||||
LunaHeader(
|
||||
text: '$_version ($_buildNumber)', subtitle: _changelog.motd),
|
||||
if (_version == null || _buildNumber == null)
|
||||
LunaHeader(text: 'LunaSea', subtitle: _changelog.motd),
|
||||
if ((_changelog.changesNew?.length ?? 0) != 0)
|
||||
const LunaHeader(text: 'New'),
|
||||
if ((_changelog.changesNew?.length ?? 0) != 0)
|
||||
LunaTableCard(
|
||||
content: List<LunaTableContent>.generate(
|
||||
_changelog.changesNew.length,
|
||||
(index) {
|
||||
String _body = _changelog.changesNew[index].changes
|
||||
.fold('', (d, o) => d += '${LunaUI.TEXT_BULLET}\t$o\n')
|
||||
.trim();
|
||||
return LunaTableContent(
|
||||
title: _changelog.changesNew[index].module,
|
||||
body: _body,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).catchError((error, stack) {
|
||||
LunaLogger().error('Failed to fetched changelog asset', error, stack);
|
||||
showLunaErrorSnackBar(title: 'Failed to Load Changelog', error: error);
|
||||
});
|
||||
if ((_changelog.changesTweaks?.length ?? 0) != 0)
|
||||
const LunaHeader(text: 'Tweaks'),
|
||||
if ((_changelog.changesTweaks?.length ?? 0) != 0)
|
||||
LunaTableCard(
|
||||
content: List<LunaTableContent>.generate(
|
||||
_changelog.changesTweaks.length,
|
||||
(index) {
|
||||
String _body = _changelog.changesTweaks[index].changes
|
||||
.fold('', (d, o) => d += '${LunaUI.TEXT_BULLET}\t$o\n')
|
||||
.trim();
|
||||
return LunaTableContent(
|
||||
title: _changelog.changesTweaks[index].module,
|
||||
body: _body,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
if ((_changelog.changesFixes?.length ?? 0) != 0)
|
||||
const LunaHeader(text: 'Fixes'),
|
||||
if ((_changelog.changesFixes?.length ?? 0) != 0)
|
||||
LunaTableCard(
|
||||
content: List<LunaTableContent>.generate(
|
||||
_changelog.changesFixes.length, (index) {
|
||||
String _body = _changelog.changesFixes[index].changes
|
||||
.fold('', (d, o) => d += '${LunaUI.TEXT_BULLET}\t$o\n')
|
||||
.trim();
|
||||
return LunaTableContent(
|
||||
title: _changelog.changesFixes[index].module,
|
||||
body: _body,
|
||||
);
|
||||
}),
|
||||
),
|
||||
if ((_changelog.changesPlatform?.length ?? 0) != 0)
|
||||
const LunaHeader(text: 'Platform-Specific'),
|
||||
if ((_changelog.changesPlatform?.length ?? 0) != 0)
|
||||
LunaTableCard(
|
||||
content: List<LunaTableContent>.generate(
|
||||
_changelog.changesPlatform.length,
|
||||
(index) {
|
||||
String _body = _changelog.changesPlatform[index].changes
|
||||
.fold('', (d, o) => d += '${LunaUI.TEXT_BULLET}\t$o\n')
|
||||
.trim();
|
||||
return LunaTableContent(
|
||||
title: _changelog.changesPlatform[index].module,
|
||||
body: _body,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: LunaUI.DEFAULT_MARGIN_SIZE / 2),
|
||||
],
|
||||
actionBar: LunaBottomActionBar(
|
||||
actions: [
|
||||
LunaButton.text(
|
||||
text: 'Full Changelog',
|
||||
icon: Icons.track_changes_rounded,
|
||||
onTap: LunaLinks.CHANGELOG.launch,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LunaLogger {
|
||||
@@ -10,13 +10,10 @@ class LunaLogger {
|
||||
|
||||
/// Initialize the logger by setting the timestamp format and capturing errors on [FlutterError.onError].
|
||||
void initialize() {
|
||||
LunaFirebaseAnalytics().setEnabledState();
|
||||
LunaFirebaseCrashlytics().setEnabledState();
|
||||
FlutterError.onError =
|
||||
(FlutterErrorDetails details, {bool forceReport = false}) async {
|
||||
if (kDebugMode)
|
||||
FlutterError.dumpErrorToConsole(details, forceReport: forceReport);
|
||||
recordCrashlyticsFlutterError(details);
|
||||
Zone.current.handleUncaughtError(details.exception, details.stack);
|
||||
};
|
||||
_compactDatabase();
|
||||
@@ -41,7 +38,7 @@ class LunaLogger {
|
||||
if (log != null) logs.add(log.toMap());
|
||||
});
|
||||
// Create a string
|
||||
JsonEncoder encoder = const JsonEncoder.withIndent(' ');
|
||||
JsonEncoder encoder = JsonEncoder.withIndent(' '.repeat(4));
|
||||
String data = encoder.convert(logs);
|
||||
return data;
|
||||
}
|
||||
@@ -49,36 +46,6 @@ class LunaLogger {
|
||||
/// Clear all logs currently saved to the database.
|
||||
Future<void> clearLogs() async => Database().clearLogsBox();
|
||||
|
||||
/// Records a Crashlytics error if it passes the following checks:
|
||||
/// - In release mode
|
||||
/// - Crashlytics is enabled in the instance
|
||||
/// - Crashlytics is enabled in Hive
|
||||
/// - The error is not a DioError
|
||||
Future<void> recordCrashlyticsError(
|
||||
dynamic error, StackTrace stackTrace) async {
|
||||
if (kReleaseMode &&
|
||||
LunaFirebaseCrashlytics.isPlatformCompatible &&
|
||||
LunaFirebaseCrashlytics.instance.isCrashlyticsCollectionEnabled &&
|
||||
LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS.data &&
|
||||
error is! DioError)
|
||||
LunaFirebaseCrashlytics.instance.recordError(error, stackTrace);
|
||||
}
|
||||
|
||||
/// Records a Crashlytics flutter error if it passes the following checks:
|
||||
/// - In release mode
|
||||
/// - Crashlytics is enabled in the instance
|
||||
/// - Crashlytics is enabled in Hive
|
||||
/// - The error is not a DioError
|
||||
Future<void> recordCrashlyticsFlutterError(
|
||||
FlutterErrorDetails details) async {
|
||||
if (kReleaseMode &&
|
||||
LunaFirebaseCrashlytics.isPlatformCompatible &&
|
||||
LunaFirebaseCrashlytics.instance.isCrashlyticsCollectionEnabled &&
|
||||
LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS.data &&
|
||||
error is! DioError)
|
||||
LunaFirebaseCrashlytics.instance.recordFlutterError(details);
|
||||
}
|
||||
|
||||
/// Log a new debug-level log.
|
||||
void debug(String message) {
|
||||
LunaLogHiveObject log = LunaLogHiveObject.withMessage(
|
||||
@@ -101,26 +68,35 @@ class LunaLogger {
|
||||
|
||||
/// Log a new error-level log.
|
||||
void error(String message, dynamic error, StackTrace stackTrace) {
|
||||
recordCrashlyticsError(error, stackTrace);
|
||||
LunaLogHiveObject log = LunaLogHiveObject.withError(
|
||||
type: LunaLogType.ERROR,
|
||||
message: message,
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
Database.logsBox.add(log);
|
||||
if (error is! NetworkImageLoadException) {
|
||||
LunaLogHiveObject log = LunaLogHiveObject.withError(
|
||||
type: LunaLogType.ERROR,
|
||||
message: message,
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
if (kDebugMode) {
|
||||
print(message);
|
||||
print(error);
|
||||
print(stackTrace);
|
||||
}
|
||||
Database.logsBox.add(log);
|
||||
}
|
||||
}
|
||||
|
||||
/// Log a new critical-level log.
|
||||
void critical(dynamic error, StackTrace stackTrace) {
|
||||
if (error is! DioError) {
|
||||
recordCrashlyticsError(error, stackTrace);
|
||||
if (error is! NetworkImageLoadException) {
|
||||
LunaLogHiveObject log = LunaLogHiveObject.withError(
|
||||
type: LunaLogType.CRITICAL,
|
||||
message: error?.toString() ?? 'Unknown critical error',
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
if (kDebugMode) {
|
||||
print(error);
|
||||
print(stackTrace);
|
||||
}
|
||||
Database.logsBox.add(log);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
export 'widgets/action_bar_card.dart';
|
||||
export 'widgets/expandable_list_tile.dart';
|
||||
export 'widgets/five_line_card_with_poster.dart';
|
||||
export 'widgets/four_line_card_with_poster.dart';
|
||||
export 'widgets/reorderable_list_dragger.dart';
|
||||
export 'widgets/two_line_card_with_poster.dart';
|
||||
@@ -1,189 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LunaExpandableListTile extends StatefulWidget {
|
||||
final String title;
|
||||
final List<TextSpan> collapsedSubtitles;
|
||||
final Widget collapsedTrailing;
|
||||
final Widget collapsedLeading;
|
||||
final Color backgroundColor;
|
||||
final Function onLongPress;
|
||||
final List<LunaHighlightedNode> expandedHighlightedNodes;
|
||||
final List<LunaTableContent> expandedTableContent;
|
||||
final List<LunaButton> expandedTableButtons;
|
||||
final Widget expandedCustomWidget;
|
||||
final bool initialExpanded;
|
||||
|
||||
/// Create a [LunaExpandableListTile] which is a list tile that expands into a table-style card.
|
||||
///
|
||||
/// If [expandedWidget] is supplied, that widget is used as the body within the expanded card.
|
||||
/// Any
|
||||
LunaExpandableListTile({
|
||||
Key key,
|
||||
@required this.title,
|
||||
@required this.collapsedSubtitles,
|
||||
this.collapsedTrailing,
|
||||
this.collapsedLeading,
|
||||
this.onLongPress,
|
||||
this.expandedHighlightedNodes,
|
||||
this.expandedTableContent,
|
||||
this.expandedTableButtons,
|
||||
this.expandedCustomWidget,
|
||||
this.backgroundColor,
|
||||
this.initialExpanded = false,
|
||||
}) : super(key: key) {
|
||||
assert(collapsedSubtitles != null);
|
||||
if (expandedCustomWidget == null) {
|
||||
assert(expandedTableContent != null);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<LunaExpandableListTile> {
|
||||
ExpandableController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
controller = ExpandableController(initialExpanded: widget.initialExpanded);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExpandableNotifier(
|
||||
controller: controller,
|
||||
child: Expandable(
|
||||
collapsed: collapsed(),
|
||||
expanded: expanded(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<TextSpan> _parseSubtitles() {
|
||||
if (widget.collapsedSubtitles.isEmpty) return [];
|
||||
List<TextSpan> _result = [];
|
||||
for (int i = 0; i < widget.collapsedSubtitles.length; i++) {
|
||||
_result.add(widget.collapsedSubtitles[i]);
|
||||
if (i != widget.collapsedSubtitles.length - 1) {
|
||||
_result.add(const TextSpan(text: '\n'));
|
||||
}
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
Widget collapsed() {
|
||||
return LunaListTile(
|
||||
context: context,
|
||||
title: LunaText.title(text: widget.title ?? LunaUI.TEXT_EMDASH),
|
||||
subtitle: RichText(
|
||||
text: TextSpan(
|
||||
style: const TextStyle(
|
||||
fontSize: LunaUI.FONT_SIZE_SUBTITLE,
|
||||
color: Colors.white70,
|
||||
),
|
||||
children: _parseSubtitles(),
|
||||
),
|
||||
overflow: TextOverflow.fade,
|
||||
softWrap: false,
|
||||
maxLines: widget.collapsedSubtitles.length,
|
||||
),
|
||||
onTap: controller.toggle,
|
||||
onLongPress: widget.onLongPress,
|
||||
contentPadding: widget.collapsedSubtitles.length > 1,
|
||||
trailing: widget.collapsedTrailing,
|
||||
leading: widget.collapsedLeading,
|
||||
color: widget.backgroundColor,
|
||||
);
|
||||
}
|
||||
|
||||
Widget expanded() {
|
||||
Widget child = widget.expandedCustomWidget ??
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
child: LunaText.title(
|
||||
text: widget.title ?? LunaUI.TEXT_EMDASH,
|
||||
softWrap: true,
|
||||
maxLines: 8,
|
||||
),
|
||||
padding: const EdgeInsets.only(
|
||||
bottom: 8.0, left: 12.0, right: 12.0, top: 10.0),
|
||||
),
|
||||
if (widget.expandedHighlightedNodes != null)
|
||||
Padding(
|
||||
child: Wrap(
|
||||
direction: Axis.horizontal,
|
||||
spacing: 6.0,
|
||||
runSpacing: 6.0,
|
||||
children: widget.expandedHighlightedNodes,
|
||||
),
|
||||
padding: const EdgeInsets.only(
|
||||
bottom: 8.0, left: 12.0, right: 12.0, top: 0.0),
|
||||
),
|
||||
Padding(
|
||||
child: Column(
|
||||
children: [
|
||||
...widget.expandedTableContent
|
||||
.map<Widget>((content) => Padding(
|
||||
child: content,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12.0),
|
||||
))
|
||||
.toList(),
|
||||
if (widget.expandedTableButtons != null)
|
||||
Padding(
|
||||
child: Wrap(
|
||||
children: [
|
||||
...List.generate(
|
||||
widget.expandedTableButtons.length,
|
||||
(index) {
|
||||
double widthFactor = 0.5;
|
||||
if (index ==
|
||||
(widget.expandedTableButtons.length -
|
||||
1) &&
|
||||
widget.expandedTableButtons.length.isOdd)
|
||||
widthFactor = 1;
|
||||
return FractionallySizedBox(
|
||||
child: widget.expandedTableButtons[index],
|
||||
widthFactor: widthFactor,
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 6.0),
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: const EdgeInsets.only(bottom: 6.0),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
return LunaCard(
|
||||
context: context,
|
||||
child: InkWell(
|
||||
child: child,
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
onTap: controller.toggle,
|
||||
onLongPress: widget.onLongPress,
|
||||
),
|
||||
color: widget.backgroundColor,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LunaFiveLineCardWithPoster extends StatelessWidget {
|
||||
final Function onTap;
|
||||
final Function onLongPress;
|
||||
final String backgroundUrl;
|
||||
final String posterUrl;
|
||||
final String posterPlaceholder;
|
||||
final String title;
|
||||
final TextSpan subtitle1;
|
||||
final TextSpan subtitle2;
|
||||
final TextSpan subtitle3;
|
||||
final TextSpan subtitle4;
|
||||
final int subtitle1MaxLines;
|
||||
final int subtitle2MaxLines;
|
||||
final int subtitle3MaxLines;
|
||||
final int subtitle4MaxLines;
|
||||
final Widget customSubtitle1;
|
||||
final Widget customSubtitle2;
|
||||
final Widget customSubtitle3;
|
||||
final Widget customSubtitle4;
|
||||
final bool darken;
|
||||
final Color titleColor;
|
||||
final Map posterHeaders;
|
||||
final LunaIconButton trailing;
|
||||
static const double itemExtent = 105.0;
|
||||
static const double _padding = 8.0;
|
||||
|
||||
const LunaFiveLineCardWithPoster({
|
||||
Key key,
|
||||
@required this.posterPlaceholder,
|
||||
@required this.posterUrl,
|
||||
@required this.posterHeaders,
|
||||
@required this.title,
|
||||
this.backgroundUrl,
|
||||
this.titleColor = Colors.white,
|
||||
this.subtitle1,
|
||||
this.subtitle2,
|
||||
this.subtitle3,
|
||||
this.subtitle4,
|
||||
this.subtitle1MaxLines = 1,
|
||||
this.subtitle2MaxLines = 1,
|
||||
this.subtitle3MaxLines = 1,
|
||||
this.subtitle4MaxLines = 1,
|
||||
this.customSubtitle1,
|
||||
this.customSubtitle2,
|
||||
this.customSubtitle3,
|
||||
this.customSubtitle4,
|
||||
this.darken = false,
|
||||
this.onTap,
|
||||
this.onLongPress,
|
||||
this.trailing,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LunaCard(
|
||||
context: context,
|
||||
child: InkWell(
|
||||
child: Row(
|
||||
children: [
|
||||
_poster(context),
|
||||
_body(context),
|
||||
if (trailing != null) _trailing(),
|
||||
],
|
||||
),
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
),
|
||||
decoration: backgroundUrl == null
|
||||
? null
|
||||
: LunaCardDecoration(
|
||||
uri: backgroundUrl,
|
||||
headers: posterHeaders,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _poster(BuildContext context) {
|
||||
return LunaNetworkImage(
|
||||
url: posterUrl,
|
||||
placeholderAsset: posterPlaceholder,
|
||||
height: itemExtent,
|
||||
width: itemExtent / 1.5,
|
||||
headers: posterHeaders,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _body(BuildContext context) {
|
||||
return Expanded(
|
||||
child: Padding(
|
||||
child: SizedBox(
|
||||
child: Column(
|
||||
children: [
|
||||
_title(),
|
||||
if (customSubtitle1 != null) customSubtitle1,
|
||||
if (customSubtitle1 == null && subtitle1 != null)
|
||||
_subtitle(subtitle1, subtitle1MaxLines),
|
||||
if (customSubtitle2 != null) customSubtitle2,
|
||||
if (customSubtitle2 == null && subtitle2 != null)
|
||||
_subtitle(subtitle2, subtitle2MaxLines),
|
||||
if (customSubtitle3 != null) customSubtitle3,
|
||||
if (customSubtitle3 == null && subtitle3 != null)
|
||||
_subtitle(subtitle3, subtitle3MaxLines),
|
||||
if (customSubtitle4 != null) customSubtitle4,
|
||||
if (customSubtitle4 == null && subtitle4 != null)
|
||||
_subtitle(subtitle4, subtitle4MaxLines),
|
||||
],
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
),
|
||||
height: (itemExtent - (_padding * 2)),
|
||||
),
|
||||
padding: const EdgeInsets.all(_padding),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _title() {
|
||||
return LunaText.title(
|
||||
text: title,
|
||||
color: titleColor,
|
||||
darken: darken,
|
||||
maxLines: 1,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _subtitle(TextSpan text, int maxLines) {
|
||||
return RichText(
|
||||
text: TextSpan(
|
||||
style: TextStyle(
|
||||
fontSize: LunaUI.FONT_SIZE_SUBTITLE,
|
||||
color: darken ? Colors.white30 : Colors.white70,
|
||||
),
|
||||
children: [text],
|
||||
),
|
||||
overflow: TextOverflow.fade,
|
||||
softWrap: maxLines == 1 ? false : true,
|
||||
maxLines: maxLines,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _trailing() {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(right: LunaUI.MARGIN_CARD.right),
|
||||
child: SizedBox(
|
||||
width: 48.0,
|
||||
height: itemExtent,
|
||||
child: trailing,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LunaFourLineCardWithPoster extends StatelessWidget {
|
||||
final Function onTap;
|
||||
final Function onLongPress;
|
||||
final String backgroundUrl;
|
||||
final String posterUrl;
|
||||
final String posterPlaceholder;
|
||||
final String title;
|
||||
final TextSpan subtitle1;
|
||||
final TextSpan subtitle2;
|
||||
final TextSpan subtitle3;
|
||||
final int subtitle1MaxLines;
|
||||
final int subtitle2MaxLines;
|
||||
final int subtitle3MaxLines;
|
||||
final Widget customSubtitle1;
|
||||
final Widget customSubtitle2;
|
||||
final Widget customSubtitle3;
|
||||
final bool darken;
|
||||
final Color titleColor;
|
||||
final Map posterHeaders;
|
||||
final LunaIconButton trailing;
|
||||
static const double itemExtent = 90.0;
|
||||
static const double padding = 8.0;
|
||||
|
||||
const LunaFourLineCardWithPoster({
|
||||
Key key,
|
||||
@required this.posterPlaceholder,
|
||||
@required this.posterUrl,
|
||||
@required this.posterHeaders,
|
||||
@required this.title,
|
||||
this.backgroundUrl,
|
||||
this.titleColor = Colors.white,
|
||||
this.subtitle1,
|
||||
this.subtitle2,
|
||||
this.subtitle3,
|
||||
this.subtitle1MaxLines = 1,
|
||||
this.subtitle2MaxLines = 1,
|
||||
this.subtitle3MaxLines = 1,
|
||||
this.customSubtitle1,
|
||||
this.customSubtitle2,
|
||||
this.customSubtitle3,
|
||||
this.darken = false,
|
||||
this.onTap,
|
||||
this.onLongPress,
|
||||
this.trailing,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LunaCard(
|
||||
context: context,
|
||||
child: InkWell(
|
||||
child: Row(
|
||||
children: [
|
||||
_poster(context),
|
||||
_body(context),
|
||||
if (trailing != null) _trailing(),
|
||||
],
|
||||
),
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
),
|
||||
decoration: backgroundUrl == null
|
||||
? null
|
||||
: LunaCardDecoration(
|
||||
uri: backgroundUrl,
|
||||
headers: posterHeaders,
|
||||
),
|
||||
height: itemExtent,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _poster(BuildContext context) {
|
||||
return LunaNetworkImage(
|
||||
url: posterUrl,
|
||||
placeholderAsset: posterPlaceholder,
|
||||
height: itemExtent,
|
||||
width: itemExtent / 1.5,
|
||||
headers: posterHeaders,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _body(BuildContext context) {
|
||||
return Expanded(
|
||||
child: Padding(
|
||||
child: SizedBox(
|
||||
child: Column(
|
||||
children: [
|
||||
_title(),
|
||||
if (customSubtitle1 != null) customSubtitle1,
|
||||
if (customSubtitle1 == null && subtitle1 != null)
|
||||
_subtitle(subtitle1, subtitle1MaxLines),
|
||||
if (customSubtitle2 != null) customSubtitle2,
|
||||
if (customSubtitle2 == null && subtitle2 != null)
|
||||
_subtitle(subtitle2, subtitle2MaxLines),
|
||||
if (customSubtitle3 != null) customSubtitle3,
|
||||
if (customSubtitle3 == null && subtitle3 != null)
|
||||
_subtitle(subtitle3, subtitle3MaxLines),
|
||||
],
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
),
|
||||
height: (itemExtent - (padding * 2)),
|
||||
),
|
||||
padding: const EdgeInsets.all(padding),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _title() {
|
||||
return LunaText.title(
|
||||
text: title,
|
||||
color: titleColor,
|
||||
darken: darken,
|
||||
maxLines: 1,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _subtitle(TextSpan text, int maxLines) {
|
||||
return RichText(
|
||||
text: TextSpan(
|
||||
style: TextStyle(
|
||||
fontSize: LunaUI.FONT_SIZE_SUBTITLE,
|
||||
color: darken ? Colors.white30 : Colors.white70,
|
||||
),
|
||||
children: [text],
|
||||
),
|
||||
overflow: TextOverflow.fade,
|
||||
softWrap: maxLines == 1 ? false : true,
|
||||
maxLines: maxLines,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _trailing() {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(right: LunaUI.MARGIN_CARD.right),
|
||||
child: SizedBox(
|
||||
width: 48.0,
|
||||
height: itemExtent,
|
||||
child: trailing,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LunaTwoLineCardWithPoster extends StatelessWidget {
|
||||
final Function onTap;
|
||||
final Function onLongPress;
|
||||
final String backgroundUrl;
|
||||
final String posterUrl;
|
||||
final String posterPlaceholder;
|
||||
final String title;
|
||||
final TextSpan subtitle1;
|
||||
final TextSpan subtitle2;
|
||||
final Widget customSubtitle1;
|
||||
final Widget customSubtitle2;
|
||||
final bool darken;
|
||||
final Color titleColor;
|
||||
final Map posterHeaders;
|
||||
final LunaIconButton trailing;
|
||||
static const double itemExtent = 67.0;
|
||||
static const double _padding = 8.0;
|
||||
|
||||
const LunaTwoLineCardWithPoster({
|
||||
Key key,
|
||||
@required this.posterPlaceholder,
|
||||
@required this.posterUrl,
|
||||
@required this.posterHeaders,
|
||||
@required this.title,
|
||||
this.backgroundUrl,
|
||||
this.titleColor = Colors.white,
|
||||
this.subtitle1,
|
||||
this.subtitle2,
|
||||
this.customSubtitle1,
|
||||
this.customSubtitle2,
|
||||
this.darken = false,
|
||||
this.onTap,
|
||||
this.onLongPress,
|
||||
this.trailing,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LunaCard(
|
||||
context: context,
|
||||
child: InkWell(
|
||||
child: Row(
|
||||
children: [
|
||||
_poster(context),
|
||||
_body(context),
|
||||
if (trailing != null) _trailing(),
|
||||
],
|
||||
),
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
),
|
||||
decoration: backgroundUrl == null
|
||||
? null
|
||||
: LunaCardDecoration(
|
||||
uri: backgroundUrl,
|
||||
headers: posterHeaders,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _poster(BuildContext context) {
|
||||
return LunaNetworkImage(
|
||||
url: posterUrl,
|
||||
placeholderAsset: posterPlaceholder,
|
||||
height: itemExtent,
|
||||
width: itemExtent,
|
||||
headers: posterHeaders,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _body(BuildContext context) {
|
||||
return Expanded(
|
||||
child: Padding(
|
||||
child: SizedBox(
|
||||
child: Column(
|
||||
children: [
|
||||
_title(),
|
||||
if (customSubtitle1 != null) customSubtitle1,
|
||||
if (customSubtitle1 == null && subtitle1 != null)
|
||||
_subtitle(subtitle1),
|
||||
if (customSubtitle2 != null) customSubtitle2,
|
||||
if (customSubtitle2 == null && subtitle2 != null)
|
||||
_subtitle(subtitle2),
|
||||
],
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
),
|
||||
height: (itemExtent - (_padding * 2)),
|
||||
),
|
||||
padding: const EdgeInsets.all(_padding),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _title() {
|
||||
return LunaText.title(
|
||||
text: title,
|
||||
color: titleColor,
|
||||
darken: darken,
|
||||
maxLines: 1,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _subtitle(TextSpan text) {
|
||||
return RichText(
|
||||
text: TextSpan(
|
||||
style: TextStyle(
|
||||
fontSize: LunaUI.FONT_SIZE_SUBTITLE,
|
||||
color: darken ? Colors.white30 : Colors.white70,
|
||||
),
|
||||
children: [text],
|
||||
),
|
||||
overflow: TextOverflow.fade,
|
||||
softWrap: false,
|
||||
maxLines: 1,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _trailing() {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(right: LunaUI.MARGIN_CARD.right),
|
||||
child: SizedBox(
|
||||
width: 48.0,
|
||||
height: itemExtent,
|
||||
child: trailing,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||