mirror of
https://github.com/jagandeepbrar/lunasea.git
synced 2026-08-31 04:32:32 +00:00
(feat): [Radarr] Ability to view and manage the queue (#414)
* (queue): Ability to view basic queue, delete queue record * (fix): [UI] Show mouse cursor on ListTile when onTap or onLongPress are not null * (fix): [UI] Fix height/width of sorting/filtering buttons, ensure consistent fixed-height for input bars * (fix): [Lists] Remove default drag handles from ReorderableListView * (fix): Further safe-guarded with platform checks * (fix): Hide settings options on incompatible platforms * (chore): Update CHANGELOG.md * (fix): Switch from package_info to package_info_plus to support MacOS and other platforms * (chore): Update packages * (chore): Update Podfile * (tweak): [Icons] Add font_awesome_flutter, change Icon() usages to FaIcon() to prepare * (tweak): [Sonarr/Queue] Utilize a cleaner messages dialog view * (feat): [Radarr/Queue] Add movie name and quality profile to collapsed tile * (fix): [UI/AppBar] Back button was top-left aligned instead of centered * (feat): [Icons] Add FontAwesome Pro icons * (tweak): [Icons] Rollback to FontAwesome 5 * (tweak): [Icons] Rollback to FontAwesome 5 * (fix): [Icons] Revert back to system icons for now * (fix): [Icons] Revert from FaIcon to Icon * (tweak): [UI/Expandable Tile] Show two buttons per line, wrapping to a new line when necessary * (feat): [Radarr] Queue implementation finished * (fix): [Queue] Safe-guard some data model usages * (chore): Update CHANGELOG.md
This commit is contained in:
@@ -4,3 +4,9 @@ android/key.properties
|
||||
ios/ExportOptions.plist
|
||||
ios/GoogleService-Info.plist
|
||||
macos/GoogleService-Info.plist
|
||||
vendor/font_awesome_flutter/icons.json
|
||||
vendor/font_awesome_flutter/lib/fonts/fa-brands-400.ttf
|
||||
vendor/font_awesome_flutter/lib/fonts/fa-duotone-900.ttf
|
||||
vendor/font_awesome_flutter/lib/fonts/fa-light-300.ttf
|
||||
vendor/font_awesome_flutter/lib/fonts/fa-regular-400.ttf
|
||||
vendor/font_awesome_flutter/lib/fonts/fa-solid-900.ttf
|
||||
|
||||
11
.gitignore
vendored
11
.gitignore
vendored
@@ -48,9 +48,16 @@ ios/build/
|
||||
/.blackbox/pubring.gpg~
|
||||
/.blackbox/pubring.kbx~
|
||||
/.blackbox/secring.gpg
|
||||
/ios/ExportOptions.plist
|
||||
/ios/GoogleService-Info.plist
|
||||
/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-brands-400.ttf
|
||||
/vendor/font_awesome_flutter/lib/fonts/fa-duotone-900.ttf
|
||||
/vendor/font_awesome_flutter/lib/fonts/fa-light-300.ttf
|
||||
/vendor/font_awesome_flutter/lib/fonts/fa-regular-400.ttf
|
||||
/vendor/font_awesome_flutter/lib/fonts/fa-solid-900.ttf
|
||||
/vendor/font_awesome_flutter/lib/fonts/fa-thin-100.ttf
|
||||
/vendor/font_awesome_flutter/icons.json
|
||||
|
||||
@@ -3,16 +3,23 @@
|
||||
## GitHub
|
||||
|
||||
#### NEW
|
||||
- `[Radarr/Queue]` Ability to view and manage the queue
|
||||
|
||||
#### TWEAKS
|
||||
|
||||
#### FIXES
|
||||
- `[Radarr/Catalogue]` Update filters to more closely match the web GUI filtering
|
||||
- `[UI/UX]` Search and filter/sort buttons now have fixed heights to have consistency across platforms
|
||||
- `[UI/UX]` Show click cursor on all clickable tiles
|
||||
- `[UI/UX]` Show two buttons per line on expandable tiles
|
||||
|
||||
#### PLATFORM SPECIFIC
|
||||
- `[macOS]` (new) Added LunaSea icon
|
||||
- `[macOS]` (fix) Set application/window title
|
||||
- `[macOS]` (fix) Add platform compatability checks for Firebase Analytics & in-app purchases
|
||||
- `[macOS]` (fix) Utilize package_info_plus to allow internal version checking
|
||||
- `[macOS]` (fix) Hide incompatible settings options
|
||||
|
||||
---
|
||||
|
||||
## v5.0.0 (50000014)
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
"radarr.InCinemasIn": "In Cinemas in {}",
|
||||
"radarr.InCinemasToday": "In Cinemas Today",
|
||||
"radarr.Interactive": "Interactive",
|
||||
"radarr.Language": "Language",
|
||||
"radarr.Languages": "Languages",
|
||||
"radarr.ManualImport": "Manual Import",
|
||||
"radarr.ManualImportDescription": "Import Movies from the Filesystem",
|
||||
|
||||
@@ -66,7 +66,7 @@ PODS:
|
||||
- Firebase/Analytics (= 7.3.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_auth (1.0.2):
|
||||
- firebase_auth (1.0.3):
|
||||
- Firebase/Auth (= 7.3.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
@@ -81,7 +81,7 @@ PODS:
|
||||
- Firebase/Messaging (= 7.3.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_storage (8.0.2):
|
||||
- firebase_storage (8.0.3):
|
||||
- Firebase/Storage (= 7.3.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
@@ -187,7 +187,7 @@ PODS:
|
||||
- nanopb/encode (2.30906.0)
|
||||
- network_info_plus (0.0.1):
|
||||
- Flutter
|
||||
- package_info (0.0.1):
|
||||
- package_info_plus (0.4.5):
|
||||
- Flutter
|
||||
- path_provider (0.0.1):
|
||||
- Flutter
|
||||
@@ -222,7 +222,7 @@ DEPENDENCIES:
|
||||
- GoogleUtilities
|
||||
- in_app_purchase (from `.symlinks/plugins/in_app_purchase/ios`)
|
||||
- network_info_plus (from `.symlinks/plugins/network_info_plus/ios`)
|
||||
- package_info (from `.symlinks/plugins/package_info/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider (from `.symlinks/plugins/path_provider/ios`)
|
||||
- quick_actions (from `.symlinks/plugins/quick_actions/ios`)
|
||||
- share (from `.symlinks/plugins/share/ios`)
|
||||
@@ -281,8 +281,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/in_app_purchase/ios"
|
||||
network_info_plus:
|
||||
:path: ".symlinks/plugins/network_info_plus/ios"
|
||||
package_info:
|
||||
:path: ".symlinks/plugins/package_info/ios"
|
||||
package_info_plus:
|
||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||
path_provider:
|
||||
:path: ".symlinks/plugins/path_provider/ios"
|
||||
quick_actions:
|
||||
@@ -307,11 +307,11 @@ SPEC CHECKSUMS:
|
||||
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
|
||||
Firebase: 26223c695fe322633274198cb19dca8cb7e54416
|
||||
firebase_analytics: ee4abb07bfa857e7c95d97144efe9eb68be414cd
|
||||
firebase_auth: 9e9e667b904ee5701ab50330a5718cce0bf1a469
|
||||
firebase_auth: c2c27e1081671b02f90981e70dad54722198491f
|
||||
firebase_core: b5d81dfd4fb2d6f700e67de34d9a633ae325c4e9
|
||||
firebase_crashlytics: 3b8018f6c88a59be95f9e2f38f04e5c0f05e0c6a
|
||||
firebase_messaging: 7547c99f31466371f9cfcb733d5a1bf32a819872
|
||||
firebase_storage: 78b9c7d73a4e75a9bed8697fab8424979e31d7dd
|
||||
firebase_storage: 2ce2146c1fa764e68330e6998fa386522c95d199
|
||||
FirebaseAnalytics: 2580c2d62535ae7b644143d48941fcc239ea897a
|
||||
FirebaseAuth: c224a0cf1afa0949bd5c7bfcf154b4f5ce8ddef2
|
||||
FirebaseCore: 4d3c72622ce0e2106aaa07bb4b2935ba2c370972
|
||||
@@ -330,7 +330,7 @@ SPEC CHECKSUMS:
|
||||
in_app_purchase: 3e2155afa9d03d4fa32d9e62d567885080ce97d6
|
||||
nanopb: 1bf24dd71191072e120b83dd02d08f3da0d65e53
|
||||
network_info_plus: b78876159360f5580608c2cea620d6ceffabd0ad
|
||||
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
|
||||
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
|
||||
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
|
||||
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
|
||||
quick_actions: 6cb2390c4dab0e737c94573c27e18d9666710720
|
||||
|
||||
@@ -452,7 +452,7 @@
|
||||
"${BUILT_PRODUCTS_DIR}/in_app_purchase/in_app_purchase.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/network_info_plus/network_info_plus.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/package_info/package_info.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/share.framework",
|
||||
@@ -483,7 +483,7 @@
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/in_app_purchase.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/network_info_plus.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info.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.framework",
|
||||
|
||||
@@ -91,6 +91,25 @@ class LunaDialogs {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> showMessages(BuildContext context, List<String> messages) async {
|
||||
if((messages ?? []).isEmpty) return textPreview(context, 'Messages', 'No messages found');
|
||||
await LunaDialog.dialog(
|
||||
context: context,
|
||||
title: 'Messages',
|
||||
cancelButtonText: 'Close',
|
||||
content: List.generate(
|
||||
messages.length,
|
||||
(index) => LunaDialog.tile(
|
||||
text: messages[index],
|
||||
icon: Icons.info_outline_rounded,
|
||||
iconColor: LunaColours.accent,
|
||||
),
|
||||
),
|
||||
contentPadding: LunaDialog.listDialogContentPadding(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// **Will be removed in future**
|
||||
///
|
||||
/// Show a delete catalogue with all files warning dialog.
|
||||
|
||||
@@ -29,5 +29,7 @@ class LunaFirebaseAnalytics {
|
||||
}
|
||||
|
||||
/// Log an "app_open" event.
|
||||
Future<void> appOpened() async => instance.logAppOpen();
|
||||
Future<void> appOpened() async {
|
||||
if(isPlatformCompatible) instance.logAppOpen();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
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 => !Platform.isLinux && !Platform.isMacOS && !Platform.isWindows;
|
||||
|
||||
/// Returns an instance of [FirebaseCrashlytics].
|
||||
///
|
||||
/// Throws an error if [LunaFirebase.initialize] has not been called.
|
||||
@@ -11,8 +15,10 @@ class LunaFirebaseCrashlytics {
|
||||
/// Set the enabled state of Firebase Crashlytics.
|
||||
///
|
||||
/// If `enabled` is set to false, force-disables Analytics.
|
||||
void setEnabledState({ bool enabled = true }) {
|
||||
bool state = kReleaseMode && LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS.data;
|
||||
instance.setCrashlyticsCollectionEnabled(state && enabled);
|
||||
void setEnabledState() {
|
||||
if(isPlatformCompatible) {
|
||||
bool state = kReleaseMode && LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS.data;
|
||||
instance.setCrashlyticsCollectionEnabled(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
import 'dart:io';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:quick_actions/quick_actions.dart';
|
||||
|
||||
class LunaQuickActions {
|
||||
static final QuickActions _quickActions = QuickActions();
|
||||
|
||||
static bool get isPlatformCompatible => Platform.isAndroid || Platform.isIOS;
|
||||
|
||||
/// Initialize the quick actions by setting the action handler.
|
||||
///
|
||||
/// Required before the handler can actually receive any intents.
|
||||
void initialize() {
|
||||
_quickActions.initialize((action) => _handler(action));
|
||||
if(isPlatformCompatible) _quickActions.initialize((action) => _handler(action));
|
||||
setShortcutItems();
|
||||
}
|
||||
|
||||
/// Sets the shortcut items by checking the database and enabling the respective action if enabled.
|
||||
void setShortcutItems() {
|
||||
_quickActions.setShortcutItems(<ShortcutItem>[
|
||||
if(isPlatformCompatible) _quickActions.setShortcutItems(<ShortcutItem>[
|
||||
if(LunaDatabaseValue.QUICK_ACTIONS_SEARCH.data) LunaModule.SEARCH.shortcutItem,
|
||||
if(LunaDatabaseValue.QUICK_ACTIONS_LIDARR.data) LunaModule.LIDARR.shortcutItem,
|
||||
if(LunaDatabaseValue.QUICK_ACTIONS_RADARR.data) LunaModule.RADARR.shortcutItem,
|
||||
|
||||
@@ -204,7 +204,9 @@ class _State extends State<LunaAppBar> {
|
||||
},
|
||||
);
|
||||
return InkWell(
|
||||
child: Icon(Icons.arrow_back_ios_rounded),
|
||||
child: Center(
|
||||
child: Icon(Icons.arrow_back_ios_rounded),
|
||||
),
|
||||
onTap: () async {
|
||||
HapticFeedback.lightImpact();
|
||||
Navigator.of(context).lunaSafetyPop();
|
||||
|
||||
@@ -66,21 +66,25 @@ class _State extends State<LunaBottomNavigationBar> {
|
||||
child: GNav(
|
||||
gap: 8.0,
|
||||
iconSize: 24.0,
|
||||
padding: EdgeInsets.fromLTRB(18.0, 10.0, 12.0, 10.0),
|
||||
duration: Duration(milliseconds: LunaUI.ANIMATION_SPEED),
|
||||
tabBackgroundColor: Theme.of(context).canvasColor.withOpacity(LunaUI.BUTTON_BACKGROUND_OPACITY),
|
||||
activeColor: LunaColours.accent,
|
||||
tabs: List.generate(widget.icons.length, (index) => GButton(
|
||||
icon: widget.icons[index],
|
||||
text: widget.titles[index],
|
||||
active: _index == index,
|
||||
iconSize: 22.0,
|
||||
haptic: true,
|
||||
padding: _index == index
|
||||
? EdgeInsets.all(10.0).add(EdgeInsets.only(left: 6.0))
|
||||
: EdgeInsets.all(10.0),
|
||||
iconColor: Colors.white,
|
||||
textStyle: TextStyle(
|
||||
fontWeight: LunaUI.FONT_WEIGHT_BOLD,
|
||||
fontSize: LunaUI.FONT_SIZE_NAVIGATION_BAR,
|
||||
color: Colors.white,
|
||||
),
|
||||
iconActiveColor: LunaColours.accent,
|
||||
leading: widget.leadingOnTab == null ? null : widget.leadingOnTab[index],
|
||||
)).toList(),
|
||||
tabActiveBorder: LunaUI.shouldUseBorder ? Border.all(color: Colors.white12) : null,
|
||||
|
||||
@@ -10,9 +10,15 @@ class LunaCard extends Card {
|
||||
Color color,
|
||||
Decoration decoration,
|
||||
double height,
|
||||
double width,
|
||||
}) : super(
|
||||
key: key,
|
||||
child: Container(child: child, decoration: decoration, height: height),
|
||||
child: Container(
|
||||
child: child,
|
||||
decoration: decoration,
|
||||
height: height,
|
||||
width: width,
|
||||
),
|
||||
margin: margin,
|
||||
color: color == null ? Theme.of(context).primaryColor : color,
|
||||
shape: LunaUI.shapeBorder,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
// export 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
|
||||
class LunaIcons {
|
||||
LunaIcons._();
|
||||
|
||||
@@ -3,6 +3,7 @@ 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 EdgeInsets appBarMargin = const EdgeInsets.fromLTRB(12.0, 1.0, 12.0, 12.0);
|
||||
|
||||
final TextEditingController controller;
|
||||
@@ -56,6 +57,7 @@ class _State extends State<LunaTextInputBar> {
|
||||
child: widget.isFormField ? _isForm : _isNotForm,
|
||||
),
|
||||
),
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
color: Theme.of(context).canvasColor,
|
||||
);
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ class LunaListTile extends Card {
|
||||
subtitle: subtitle,
|
||||
trailing: trailing,
|
||||
leading: leading,
|
||||
mouseCursor: onTap != null || onLongPress != null ? SystemMouseCursors.click : null,
|
||||
contentPadding: contentPadding ? customContentPadding ?? EdgeInsets.symmetric(vertical: 6.0, horizontal: 12.0) : null,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
|
||||
@@ -7,6 +7,7 @@ class LunaReorderableListView extends StatelessWidget {
|
||||
final ScrollPhysics physics;
|
||||
final ScrollController controller;
|
||||
final void Function(int, int) onReorder;
|
||||
final bool buildDefaultDragHandles;
|
||||
|
||||
LunaReorderableListView({
|
||||
Key key,
|
||||
@@ -15,6 +16,7 @@ class LunaReorderableListView extends StatelessWidget {
|
||||
@required this.onReorder,
|
||||
this.padding,
|
||||
this.physics = const AlwaysScrollableScrollPhysics(),
|
||||
this.buildDefaultDragHandles = false,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@@ -28,6 +30,7 @@ class LunaReorderableListView extends StatelessWidget {
|
||||
padding: padding ?? MediaQuery.of(context).padding.add(EdgeInsets.symmetric(vertical: 8.0)),
|
||||
physics: physics,
|
||||
onReorder: onReorder,
|
||||
buildDefaultDragHandles: buildDefaultDragHandles,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ class LunaReorderableListViewBuilder extends StatelessWidget {
|
||||
final ScrollPhysics physics;
|
||||
final ScrollController controller;
|
||||
final void Function(int, int) onReorder;
|
||||
final bool buildDefaultDragHandles;
|
||||
|
||||
LunaReorderableListViewBuilder({
|
||||
Key key,
|
||||
@@ -17,6 +18,7 @@ class LunaReorderableListViewBuilder extends StatelessWidget {
|
||||
@required this.onReorder,
|
||||
this.padding,
|
||||
this.physics = const AlwaysScrollableScrollPhysics(),
|
||||
this.buildDefaultDragHandles = false,
|
||||
}) : super(key: key) {
|
||||
assert(itemCount != null);
|
||||
assert(itemBuilder != null);
|
||||
@@ -34,6 +36,7 @@ class LunaReorderableListViewBuilder extends StatelessWidget {
|
||||
itemCount: itemCount,
|
||||
itemBuilder: itemBuilder,
|
||||
onReorder: onReorder,
|
||||
buildDefaultDragHandles: buildDefaultDragHandles,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class LunaTheme {
|
||||
accentColor: LunaColours.accent,
|
||||
highlightColor: LunaColours.splash.withOpacity(0.15),
|
||||
cardColor: LunaColours.secondary,
|
||||
hoverColor: LunaColours.splash.withOpacity(0.10),
|
||||
hoverColor: LunaColours.accent.withOpacity(0.15),
|
||||
splashColor: LunaColours.accent.withOpacity(0.30),
|
||||
dialogBackgroundColor: LunaColours.secondary,
|
||||
toggleableActiveColor: LunaColours.accent,
|
||||
@@ -43,7 +43,7 @@ class LunaTheme {
|
||||
accentColor: LunaColours.accent,
|
||||
highlightColor: LunaColours.splash.withOpacity(0.15),
|
||||
cardColor: Colors.black,
|
||||
hoverColor: LunaColours.splash.withOpacity(0.10),
|
||||
hoverColor: LunaColours.accent.withOpacity(0.15),
|
||||
splashColor: LunaColours.accent.withOpacity(0.30),
|
||||
dialogBackgroundColor: Colors.black,
|
||||
toggleableActiveColor: LunaColours.accent,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:package_info/package_info.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.
|
||||
@@ -10,7 +10,7 @@ class LunaChangelog {
|
||||
Future<void> checkAndShowChangelog() async {
|
||||
PackageInfo.fromPlatform()
|
||||
.then((package) {
|
||||
if(AlertsDatabaseValue.CHANGELOG.data != package.buildNumber) {
|
||||
if(package != null && AlertsDatabaseValue.CHANGELOG.data != package.buildNumber) {
|
||||
AlertsDatabaseValue.CHANGELOG.put(package.buildNumber);
|
||||
showChangelog(package.version, package.buildNumber);
|
||||
}
|
||||
@@ -32,7 +32,8 @@ class LunaChangelog {
|
||||
body: LunaListViewModal(
|
||||
shrinkWrap: false,
|
||||
children: [
|
||||
LunaHeader(text: '$version ($buildNumber)', subtitle: changelog.motd),
|
||||
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) LunaHeader(text: 'New'),
|
||||
if((changelog.changesNew?.length ?? 0) != 0) LunaTableCard(
|
||||
content: List<LunaTableContent>.generate(
|
||||
|
||||
@@ -61,6 +61,7 @@ class LunaLogger {
|
||||
Future<void> recordCrashlyticsError(dynamic error, StackTrace stackTrace) async {
|
||||
if(
|
||||
kReleaseMode &&
|
||||
LunaFirebaseCrashlytics.isPlatformCompatible &&
|
||||
LunaFirebaseCrashlytics.instance.isCrashlyticsCollectionEnabled &&
|
||||
LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS.data &&
|
||||
!(error is DioError)
|
||||
@@ -75,6 +76,7 @@ class LunaLogger {
|
||||
Future<void> recordCrashlyticsFlutterError(FlutterErrorDetails details) async {
|
||||
if(
|
||||
kReleaseMode &&
|
||||
LunaFirebaseCrashlytics.isPlatformCompatible &&
|
||||
LunaFirebaseCrashlytics.instance.isCrashlyticsCollectionEnabled &&
|
||||
LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS.data &&
|
||||
!(error is DioError)
|
||||
|
||||
@@ -133,14 +133,22 @@ class _State extends State<LunaExpandableListTile> {
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.0),
|
||||
)).toList(),
|
||||
if(widget.expandedTableButtons != null) Padding(
|
||||
child: Row(
|
||||
child: Wrap(
|
||||
children: [
|
||||
...widget.expandedTableButtons.map<Widget>((button) => Expanded(
|
||||
child: Padding(
|
||||
child: button,
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
)).toList(),
|
||||
...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: EdgeInsets.symmetric(horizontal: 6.0),
|
||||
|
||||
@@ -129,16 +129,6 @@ class _State extends State<DashboardCalendarWidget> {
|
||||
weekendStyle: weekdayTitleStyle,
|
||||
weekdayStyle: weekdayTitleStyle,
|
||||
),
|
||||
headerStyle: HeaderStyle(
|
||||
titleTextStyle: TextStyle(
|
||||
fontSize: LunaUI.FONT_SIZE_HEADER,
|
||||
fontWeight: LunaUI.FONT_WEIGHT_BOLD,
|
||||
),
|
||||
centerHeaderTitle: true,
|
||||
formatButtonVisible: false,
|
||||
leftChevronIcon: Icon(Icons.arrow_back_ios_rounded),
|
||||
rightChevronIcon: Icon(Icons.arrow_forward_ios_rounded),
|
||||
),
|
||||
initialCalendarFormat: (DashboardDatabaseValue.CALENDAR_STARTING_SIZE.data as CalendarStartingSize).data,
|
||||
availableCalendarFormats: const {
|
||||
CalendarFormat.month : 'Month', CalendarFormat.twoWeeks : '2 Weeks', CalendarFormat.week : 'Week'},
|
||||
|
||||
@@ -29,6 +29,8 @@ class _State extends State<LidarrCatalogueHideButton> {
|
||||
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
|
||||
),
|
||||
),
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
width: LunaTextInputBar.appBarInnerHeight,
|
||||
margin: EdgeInsets.symmetric(horizontal: 12.0),
|
||||
color: Theme.of(context).canvasColor,
|
||||
);
|
||||
|
||||
@@ -18,6 +18,8 @@ class _State extends State<LidarrCatalogueSortButton> {
|
||||
@override
|
||||
Widget build(BuildContext context) => LunaCard(
|
||||
context: context,
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
width: LunaTextInputBar.appBarInnerHeight,
|
||||
child: Consumer<LidarrState>(
|
||||
builder: (context, model, _) => LunaPopupMenuButton<LidarrCatalogueSorting>(
|
||||
tooltip: 'Sort Catalogue',
|
||||
|
||||
@@ -26,6 +26,8 @@ class _State extends State<LidarrReleasesHideButton> {
|
||||
onPressed: () => model.hideRejectedReleases = !model.hideRejectedReleases,
|
||||
),
|
||||
),
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
width: LunaTextInputBar.appBarInnerHeight,
|
||||
margin: LunaTextInputBar.appBarMargin.subtract(EdgeInsets.only(left: 12.0)),
|
||||
color: Theme.of(context).canvasColor,
|
||||
);
|
||||
|
||||
@@ -18,6 +18,8 @@ class _State extends State<LidarrReleasesSortButton> {
|
||||
@override
|
||||
Widget build(BuildContext context) => LunaCard(
|
||||
context: context,
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
width: LunaTextInputBar.appBarInnerHeight,
|
||||
child: Consumer<LidarrState>(
|
||||
builder: (context, model, _) => LunaPopupMenuButton<LidarrReleasesSorting>(
|
||||
tooltip: 'Sort Releases',
|
||||
|
||||
@@ -26,6 +26,8 @@ class _State extends State<NZBGetHistoryHideButton> {
|
||||
onPressed: () => model.historyHideFailed = !model.historyHideFailed,
|
||||
),
|
||||
),
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
width: LunaTextInputBar.appBarInnerHeight,
|
||||
margin: EdgeInsets.only(left: 12.0),
|
||||
color: Theme.of(context).canvasColor,
|
||||
);
|
||||
|
||||
@@ -44,6 +44,9 @@ class RadarrDatabase extends LunaModuleDatabase {
|
||||
case RadarrDatabaseValue.ADD_MOVIE_DEFAULT_TAGS:
|
||||
case RadarrDatabaseValue.ADD_DISCOVER_USE_SUGGESTIONS:
|
||||
case RadarrDatabaseValue.MANUAL_IMPORT_DEFAULT_MODE:
|
||||
case RadarrDatabaseValue.QUEUE_REFRESH_RATE:
|
||||
case RadarrDatabaseValue.QUEUE_BLACKLIST:
|
||||
case RadarrDatabaseValue.QUEUE_REMOVE_FROM_CLIENT:
|
||||
case RadarrDatabaseValue.REMOVE_MOVIE_IMPORT_LIST:
|
||||
case RadarrDatabaseValue.REMOVE_MOVIE_DELETE_FILES:
|
||||
case RadarrDatabaseValue.CONTENT_PAGE_SIZE: data[value.key] = value.data; break;
|
||||
@@ -76,6 +79,9 @@ class RadarrDatabase extends LunaModuleDatabase {
|
||||
case RadarrDatabaseValue.ADD_MOVIE_DEFAULT_TAGS:
|
||||
case RadarrDatabaseValue.ADD_DISCOVER_USE_SUGGESTIONS:
|
||||
case RadarrDatabaseValue.MANUAL_IMPORT_DEFAULT_MODE:
|
||||
case RadarrDatabaseValue.QUEUE_REFRESH_RATE:
|
||||
case RadarrDatabaseValue.QUEUE_BLACKLIST:
|
||||
case RadarrDatabaseValue.QUEUE_REMOVE_FROM_CLIENT:
|
||||
case RadarrDatabaseValue.REMOVE_MOVIE_DELETE_FILES:
|
||||
case RadarrDatabaseValue.REMOVE_MOVIE_IMPORT_LIST:
|
||||
case RadarrDatabaseValue.CONTENT_PAGE_SIZE: value.put(config[key]); break;
|
||||
@@ -103,6 +109,9 @@ class RadarrDatabase extends LunaModuleDatabase {
|
||||
case 'RADARR_ADD_MOVIE_DEFAULT_TAGS': return RadarrDatabaseValue.ADD_MOVIE_DEFAULT_TAGS;
|
||||
case 'RADARR_ADD_DISCOVER_USE_SUGGESTIONS': return RadarrDatabaseValue.ADD_DISCOVER_USE_SUGGESTIONS;
|
||||
case 'RADARR_MANUAL_IMPORT_DEFAULT_MODE': return RadarrDatabaseValue.MANUAL_IMPORT_DEFAULT_MODE;
|
||||
case 'RADARR_QUEUE_REFRESH_RATE': return RadarrDatabaseValue.QUEUE_REFRESH_RATE;
|
||||
case 'RADARR_QUEUE_BLACKLIST': return RadarrDatabaseValue.QUEUE_BLACKLIST;
|
||||
case 'RADARR_QUEUE_REMOVE_FROM_CLIENT': return RadarrDatabaseValue.QUEUE_REMOVE_FROM_CLIENT;
|
||||
case 'RADARR_REMOVE_MOVIE_IMPORT_LIST': return RadarrDatabaseValue.REMOVE_MOVIE_IMPORT_LIST;
|
||||
case 'RADARR_REMOVE_MOVIE_DELETE_FILES': return RadarrDatabaseValue.REMOVE_MOVIE_DELETE_FILES;
|
||||
case 'RADARR_CONTENT_PAGE_SIZE': return RadarrDatabaseValue.CONTENT_PAGE_SIZE;
|
||||
@@ -129,6 +138,9 @@ enum RadarrDatabaseValue {
|
||||
ADD_MOVIE_DEFAULT_TAGS,
|
||||
ADD_DISCOVER_USE_SUGGESTIONS,
|
||||
MANUAL_IMPORT_DEFAULT_MODE,
|
||||
QUEUE_REFRESH_RATE,
|
||||
QUEUE_BLACKLIST,
|
||||
QUEUE_REMOVE_FROM_CLIENT,
|
||||
REMOVE_MOVIE_IMPORT_LIST,
|
||||
REMOVE_MOVIE_DELETE_FILES,
|
||||
CONTENT_PAGE_SIZE,
|
||||
@@ -154,6 +166,9 @@ extension RadarrDatabaseValueExtension on RadarrDatabaseValue {
|
||||
case RadarrDatabaseValue.ADD_MOVIE_DEFAULT_TAGS: return 'RADARR_ADD_MOVIE_DEFAULT_TAGS';
|
||||
case RadarrDatabaseValue.ADD_DISCOVER_USE_SUGGESTIONS: return 'RADARR_ADD_DISCOVER_USE_SUGGESTIONS';
|
||||
case RadarrDatabaseValue.MANUAL_IMPORT_DEFAULT_MODE: return 'RADARR_MANUAL_IMPORT_DEFAULT_MODE';
|
||||
case RadarrDatabaseValue.QUEUE_REFRESH_RATE: return 'RADARR_QUEUE_REFRESH_RATE';
|
||||
case RadarrDatabaseValue.QUEUE_BLACKLIST: return 'RADARR_RADARR_QUEUE_BLACKLIST';
|
||||
case RadarrDatabaseValue.QUEUE_REMOVE_FROM_CLIENT: return 'RADARR_QUEUE_REMOVE_FROM_CLIENT';
|
||||
case RadarrDatabaseValue.REMOVE_MOVIE_IMPORT_LIST: return 'RADARR_REMOVE_MOVIE_IMPORT_LIST';
|
||||
case RadarrDatabaseValue.REMOVE_MOVIE_DELETE_FILES: return 'RADARR_REMOVE_MOVIE_DELETE_FILES';
|
||||
case RadarrDatabaseValue.CONTENT_PAGE_SIZE: return 'RADARR_CONTENT_PAGE_SIZE';
|
||||
@@ -181,6 +196,9 @@ extension RadarrDatabaseValueExtension on RadarrDatabaseValue {
|
||||
case RadarrDatabaseValue.ADD_MOVIE_DEFAULT_TAGS: return _box.get(this.key, defaultValue: []);
|
||||
case RadarrDatabaseValue.ADD_DISCOVER_USE_SUGGESTIONS: return _box.get(this.key, defaultValue: true);
|
||||
case RadarrDatabaseValue.MANUAL_IMPORT_DEFAULT_MODE: return _box.get(this.key, defaultValue: RadarrImportMode.COPY.value);
|
||||
case RadarrDatabaseValue.QUEUE_REFRESH_RATE: return _box.get(this.key, defaultValue: 60);
|
||||
case RadarrDatabaseValue.QUEUE_BLACKLIST: return _box.get(this.key, defaultValue: false);
|
||||
case RadarrDatabaseValue.QUEUE_REMOVE_FROM_CLIENT: return _box.get(this.key, defaultValue: false);
|
||||
case RadarrDatabaseValue.REMOVE_MOVIE_DELETE_FILES: return _box.get(this.key, defaultValue: false);
|
||||
case RadarrDatabaseValue.REMOVE_MOVIE_IMPORT_LIST: return _box.get(this.key, defaultValue: false);
|
||||
case RadarrDatabaseValue.CONTENT_PAGE_SIZE: return _box.get(this.key, defaultValue: 25);
|
||||
@@ -208,6 +226,9 @@ extension RadarrDatabaseValueExtension on RadarrDatabaseValue {
|
||||
case RadarrDatabaseValue.ADD_MOVIE_DEFAULT_TAGS: if(value is List) box.put(this.key, value); return;
|
||||
case RadarrDatabaseValue.ADD_DISCOVER_USE_SUGGESTIONS: if(value is bool) box.put(this.key, value); return;
|
||||
case RadarrDatabaseValue.MANUAL_IMPORT_DEFAULT_MODE: if(value is RadarrImportMode) box.put(this.key, value.value); return;
|
||||
case RadarrDatabaseValue.QUEUE_REFRESH_RATE: if(value is int) box.put(this.key, value); return;
|
||||
case RadarrDatabaseValue.QUEUE_BLACKLIST: if(value is bool) box.put(this.key, value); return;
|
||||
case RadarrDatabaseValue.QUEUE_REMOVE_FROM_CLIENT: if(value is bool) box.put(this.key, value); return;
|
||||
case RadarrDatabaseValue.REMOVE_MOVIE_DELETE_FILES: if(value is bool) box.put(this.key, value); return;
|
||||
case RadarrDatabaseValue.REMOVE_MOVIE_IMPORT_LIST: if(value is bool) box.put(this.key, value); return;
|
||||
case RadarrDatabaseValue.CONTENT_PAGE_SIZE: if(value is int) box.put(this.key, value); return;
|
||||
|
||||
@@ -427,6 +427,45 @@ class RadarrDialogs {
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> confirmDeleteQueue(BuildContext context) async {
|
||||
bool _flag = false;
|
||||
|
||||
void _setValues(bool flag) {
|
||||
_flag = flag;
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LunaDialog.dialog(
|
||||
context: context,
|
||||
title: 'Remove From Queue',
|
||||
buttons: [
|
||||
LunaDialog.button(
|
||||
text: 'Remove',
|
||||
textColor: LunaColours.red,
|
||||
onPressed: () => _setValues(true),
|
||||
),
|
||||
],
|
||||
content: [
|
||||
RadarrDatabaseValue.QUEUE_REMOVE_FROM_CLIENT.listen(
|
||||
builder: (context, box, _) => LunaDialog.checkbox(
|
||||
title: 'Remove From Client',
|
||||
value: RadarrDatabaseValue.QUEUE_REMOVE_FROM_CLIENT.data,
|
||||
onChanged: (selected) => RadarrDatabaseValue.QUEUE_REMOVE_FROM_CLIENT.put(selected),
|
||||
),
|
||||
),
|
||||
RadarrDatabaseValue.QUEUE_BLACKLIST.listen(
|
||||
builder: (context, box, _) => LunaDialog.checkbox(
|
||||
title: 'Blacklist Release',
|
||||
value: RadarrDatabaseValue.QUEUE_BLACKLIST.data,
|
||||
onChanged: (selected) => RadarrDatabaseValue.QUEUE_BLACKLIST.put(selected),
|
||||
),
|
||||
),
|
||||
],
|
||||
contentPadding: LunaDialog.listDialogContentPadding(),
|
||||
);
|
||||
return _flag;
|
||||
}
|
||||
|
||||
Future<void> setAddTags(BuildContext context) async {
|
||||
await showDialog(
|
||||
context: context,
|
||||
|
||||
@@ -8,5 +8,6 @@ export 'extensions/radarr_manual_import.dart';
|
||||
export 'extensions/radarr_movie_file.dart';
|
||||
export 'extensions/radarr_movie.dart';
|
||||
export 'extensions/radarr_quality_profile.dart';
|
||||
export 'extensions/radarr_queue_record.dart';
|
||||
export 'extensions/radarr_release.dart';
|
||||
export 'extensions/radarr_system_status.dart';
|
||||
|
||||
75
lib/modules/radarr/core/extensions/radarr_queue_record.dart
Normal file
75
lib/modules/radarr/core/extensions/radarr_queue_record.dart
Normal file
@@ -0,0 +1,75 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/radarr.dart';
|
||||
|
||||
extension LunaRadarrQueueRecord on RadarrQueueRecord {
|
||||
String get lunaQuality {
|
||||
return this.quality?.quality?.name ?? LunaUI.TEXT_EMDASH;
|
||||
}
|
||||
|
||||
String get lunaLanguage {
|
||||
if((this?.languages?.length ?? 0) == 0) return LunaUI.TEXT_EMDASH;
|
||||
if(this.languages.length == 1) return this.languages[0].name ?? LunaUI.TEXT_EMDASH;
|
||||
return 'Multi-Language';
|
||||
}
|
||||
|
||||
String lunaTitle(RadarrMovie movie) {
|
||||
String title = movie?.title ?? LunaUI.TEXT_EMDASH;
|
||||
String year = movie?.lunaYear;
|
||||
return '$title ($year)';
|
||||
}
|
||||
|
||||
String get lunaDownloadClient {
|
||||
if((this?.downloadClient ?? '').isNotEmpty) return this.downloadClient;
|
||||
return LunaUI.TEXT_EMDASH;
|
||||
}
|
||||
|
||||
String get lunaIndexer {
|
||||
if((this?.indexer ?? '').isNotEmpty) return this.indexer;
|
||||
return LunaUI.TEXT_EMDASH;
|
||||
}
|
||||
|
||||
Color get lunaProtocolColor {
|
||||
if(this.protocol == RadarrProtocol.USENET) return LunaColours.accent;
|
||||
return LunaColours.blue;
|
||||
}
|
||||
|
||||
int get lunaPercentageComplete {
|
||||
if(this.sizeLeft == null || this.size == null || this.size == 0) return 0;
|
||||
double sizeFetched = this.size - this.sizeLeft;
|
||||
return ((sizeFetched/this.size)*100).round();
|
||||
}
|
||||
|
||||
IconData get lunaStatusIcon {
|
||||
switch(this.status) {
|
||||
case RadarrQueueRecordStatus.DELAY: return Icons.access_time_rounded;
|
||||
case RadarrQueueRecordStatus.DOWNLOAD_CLIENT_UNAVAILABLE: return Icons.access_time_rounded;
|
||||
case RadarrQueueRecordStatus.FAILED: return Icons.cloud_download_rounded;
|
||||
case RadarrQueueRecordStatus.PAUSED: return Icons.pause_rounded;
|
||||
case RadarrQueueRecordStatus.QUEUED: return Icons.cloud_rounded;
|
||||
case RadarrQueueRecordStatus.WARNING: return Icons.cloud_download_rounded;
|
||||
case RadarrQueueRecordStatus.COMPLETED: return Icons.download_done_rounded;
|
||||
case RadarrQueueRecordStatus.DOWNLOADING: return Icons.cloud_download_rounded;
|
||||
default: return Icons.cloud_download_rounded;
|
||||
}
|
||||
}
|
||||
|
||||
Color get lunaStatusColor {
|
||||
Color color = Colors.white;
|
||||
if(this.status == RadarrQueueRecordStatus.COMPLETED) switch(this.trackedDownloadState) {
|
||||
case RadarrTrackedDownloadState.FAILED_PENDING: color = LunaColours.red; break;
|
||||
case RadarrTrackedDownloadState.IMPORT_PENDING: color = LunaColours.purple; break;
|
||||
case RadarrTrackedDownloadState.IMPORTING: color = LunaColours.purple; break;
|
||||
default: break;
|
||||
}
|
||||
if(this.trackedDownloadStatus == RadarrTrackedDownloadStatus.WARNING) color = LunaColours.orange;
|
||||
switch(this.status) {
|
||||
case RadarrQueueRecordStatus.DOWNLOAD_CLIENT_UNAVAILABLE: color = LunaColours.orange; break;
|
||||
case RadarrQueueRecordStatus.FAILED: color = LunaColours.red; break;
|
||||
case RadarrQueueRecordStatus.WARNING: color = LunaColours.orange; break;
|
||||
default: break;
|
||||
}
|
||||
if(this.trackedDownloadStatus == RadarrTrackedDownloadStatus.ERROR) color = LunaColours.red;
|
||||
return color;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/radarr.dart';
|
||||
|
||||
@@ -5,6 +7,12 @@ class RadarrState extends LunaModuleState {
|
||||
RadarrState() {
|
||||
reset();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_getQueueTimer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void reset() {
|
||||
@@ -17,6 +25,7 @@ class RadarrState extends LunaModuleState {
|
||||
_qualityDefinitions = null;
|
||||
_languages = null;
|
||||
_tags = null;
|
||||
_queue = null;
|
||||
// Reinitialize
|
||||
resetProfile();
|
||||
if(_enabled) {
|
||||
@@ -26,6 +35,7 @@ class RadarrState extends LunaModuleState {
|
||||
fetchLanguages();
|
||||
fetchTags();
|
||||
fetchMovies();
|
||||
fetchQueue();
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
@@ -259,6 +269,38 @@ class RadarrState extends LunaModuleState {
|
||||
if(_api != null) _tags = _api.tag.getAll();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/////////////
|
||||
/// QUEUE ///
|
||||
/////////////
|
||||
|
||||
/// Timer to handle refreshing queue data
|
||||
Timer _getQueueTimer;
|
||||
|
||||
void createQueueTimer() => _getQueueTimer = Timer.periodic(
|
||||
Duration(seconds: RadarrDatabaseValue.QUEUE_REFRESH_RATE.data),
|
||||
(_) => fetchQueue(),
|
||||
);
|
||||
|
||||
void cancelQueueTimer() => _getQueueTimer?.cancel();
|
||||
|
||||
|
||||
Future<RadarrQueue> _queue;
|
||||
Future<RadarrQueue> get queue => _queue;
|
||||
set queue(Future<RadarrQueue> queue) {
|
||||
assert(queue != null);
|
||||
_queue = queue;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void fetchQueue() {
|
||||
cancelQueueTimer();
|
||||
if(_api != null) {
|
||||
_queue = _api.queue.get();
|
||||
createQueueTimer();
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
//////////////
|
||||
/// IMAGES ///
|
||||
|
||||
@@ -42,6 +42,8 @@ class _State extends State<RadarrCatalogueSearchBarFilterButton> {
|
||||
),
|
||||
),
|
||||
),
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
width: LunaTextInputBar.appBarInnerHeight,
|
||||
margin: EdgeInsets.symmetric(horizontal: 12.0),
|
||||
color: Theme.of(context).canvasColor,
|
||||
);
|
||||
|
||||
@@ -59,6 +59,8 @@ class _State extends State<RadarrCatalogueSearchBarSortButton> {
|
||||
),
|
||||
margin: EdgeInsets.zero,
|
||||
color: Theme.of(context).canvasColor,
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
width: LunaTextInputBar.appBarInnerHeight,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
export 'queue/route.dart';
|
||||
export 'queue/widgets.dart';
|
||||
|
||||
@@ -15,21 +15,79 @@ class _RadarrQueueRoute extends StatefulWidget {
|
||||
State<StatefulWidget> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<_RadarrQueueRoute> {
|
||||
class _State extends State<_RadarrQueueRoute> with LunaLoadCallbackMixin, LunaScrollControllerMixin {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LunaScaffold(
|
||||
scaffoldKey: _scaffoldKey,
|
||||
appBar: _appBar(),
|
||||
body: LunaMessage.goBack(context: context, text: 'lunasea.ComingSoon'.tr()),
|
||||
body: _body(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> loadCallback() async {
|
||||
if(context.read<RadarrState>().enabled) {
|
||||
await context.read<RadarrState>().api.command.refreshMonitoredDownloads();
|
||||
context.read<RadarrState>().fetchQueue();
|
||||
}
|
||||
}
|
||||
|
||||
Widget _appBar() {
|
||||
return LunaAppBar(
|
||||
title: 'radarr.Queue'.tr(),
|
||||
scrollControllers: [scrollController],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _body() {
|
||||
return LunaRefreshIndicator(
|
||||
key: _refreshKey,
|
||||
context: context,
|
||||
onRefresh: loadCallback,
|
||||
child: FutureBuilder(
|
||||
future: Future.wait([
|
||||
context.select((RadarrState state) => state.queue),
|
||||
context.select((RadarrState state) => state.movies),
|
||||
]),
|
||||
builder: (context, AsyncSnapshot<List> snapshot) {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) LunaLogger().error(
|
||||
'Unable to fetch Radarr queue',
|
||||
snapshot.error,
|
||||
snapshot.stackTrace,
|
||||
);
|
||||
return LunaMessage.error(onTap: _refreshKey.currentState?.show);
|
||||
}
|
||||
if(snapshot.hasData) return _list(snapshot.data[0], snapshot.data[1]);
|
||||
return LunaLoader();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _list(RadarrQueue queue, List<RadarrMovie> movies) {
|
||||
if((queue?.records?.length ?? 0) == 0) return LunaMessage(
|
||||
text: 'Empty Queue',
|
||||
buttonText: 'lunasea.Refresh'.tr(),
|
||||
onTap: _refreshKey.currentState?.show,
|
||||
);
|
||||
return LunaListViewBuilder(
|
||||
controller: scrollController,
|
||||
itemCount: queue.records.length,
|
||||
itemBuilder: (context, index) {
|
||||
RadarrMovie movie = movies.firstWhere(
|
||||
(movie) => movie.id == queue.records[index].movieId,
|
||||
orElse: () => null,
|
||||
);
|
||||
return RadarrQueueTile(
|
||||
record: queue.records[index],
|
||||
movie: movie,
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
1
lib/modules/radarr/routes/queue/widgets.dart
Normal file
1
lib/modules/radarr/routes/queue/widgets.dart
Normal file
@@ -0,0 +1 @@
|
||||
export 'widgets/queue_tile.dart';
|
||||
140
lib/modules/radarr/routes/queue/widgets/queue_tile.dart
Normal file
140
lib/modules/radarr/routes/queue/widgets/queue_tile.dart
Normal file
@@ -0,0 +1,140 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/radarr.dart';
|
||||
|
||||
class RadarrQueueTile extends StatelessWidget {
|
||||
final RadarrQueueRecord record;
|
||||
final RadarrMovie movie;
|
||||
|
||||
RadarrQueueTile({
|
||||
Key key,
|
||||
@required this.record,
|
||||
@required this.movie,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: context.watch<RadarrState>().movies,
|
||||
builder: (context, AsyncSnapshot<List<RadarrMovie>> snapshot) {
|
||||
RadarrMovie movie;
|
||||
if(snapshot.hasData) movie = snapshot.data.firstWhere(
|
||||
(element) => element.id == record.movieId,
|
||||
orElse: () => null,
|
||||
);
|
||||
return LunaExpandableListTile(
|
||||
title: record.title,
|
||||
collapsedSubtitle1: _subtitle1(),
|
||||
collapsedSubtitle2: _subtitle2(),
|
||||
expandedHighlightedNodes: _highlightedNodes(),
|
||||
expandedTableContent: _tableContent(movie),
|
||||
expandedTableButtons: _tableButtons(context),
|
||||
collapsedTrailing: LunaIconButton(
|
||||
icon: record.lunaStatusIcon,
|
||||
color: record.lunaStatusColor,
|
||||
),
|
||||
onLongPress: () async => RadarrMoviesDetailsRouter().navigateTo(context, movieId: record.movieId),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
TextSpan _subtitle1() {
|
||||
return TextSpan(text: record?.lunaTitle(movie) ?? LunaUI.TEXT_EMDASH);
|
||||
}
|
||||
|
||||
TextSpan _subtitle2() {
|
||||
return TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: record.lunaQuality,
|
||||
style: TextStyle(
|
||||
color: LunaColours.accent,
|
||||
fontWeight: LunaUI.FONT_WEIGHT_BOLD,
|
||||
),
|
||||
),
|
||||
TextSpan(text: LunaUI.TEXT_BULLET.lunaPad()),
|
||||
TextSpan(text: record?.timeLeft ?? LunaUI.TEXT_EMDASH),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
List<LunaTableContent> _tableContent(RadarrMovie movie) {
|
||||
return [
|
||||
LunaTableContent(title: 'radarr.Movie'.tr(), body: record?.lunaTitle(movie)),
|
||||
LunaTableContent(title: 'radarr.Languages'.tr(), body: record.lunaLanguage),
|
||||
LunaTableContent(title: 'Client', body: record.lunaDownloadClient),
|
||||
LunaTableContent(title: 'Indexer', body: record.lunaIndexer),
|
||||
LunaTableContent(title: 'radarr.Size'.tr(), body: record.size.toInt().lunaBytesToString()),
|
||||
LunaTableContent(title: 'Time Left', body: record.timeLeft ?? LunaUI.TEXT_EMDASH),
|
||||
];
|
||||
}
|
||||
|
||||
List<LunaHighlightedNode> _highlightedNodes() {
|
||||
return [
|
||||
LunaHighlightedNode(
|
||||
text: record.protocol?.readable ?? LunaUI.TEXT_EMDASH,
|
||||
backgroundColor: LunaColours.blue,
|
||||
),
|
||||
LunaHighlightedNode(
|
||||
text: record.lunaQuality,
|
||||
backgroundColor: LunaColours.accent,
|
||||
),
|
||||
if((record.customFormats?.length ?? 0) != 0) for(int i=0; i<record.customFormats.length; i++) LunaHighlightedNode(
|
||||
text: record.customFormats[i].name,
|
||||
backgroundColor: LunaColours.orange,
|
||||
),
|
||||
LunaHighlightedNode(
|
||||
text: '${record?.lunaPercentageComplete ?? LunaUI.TEXT_EMDASH}%',
|
||||
backgroundColor: LunaColours.blueGrey,
|
||||
),
|
||||
LunaHighlightedNode(
|
||||
text: record?.status?.readable ?? LunaUI.TEXT_EMDASH,
|
||||
backgroundColor: LunaColours.blueGrey,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<LunaButton> _tableButtons(BuildContext context) {
|
||||
return [
|
||||
if((record?.statusMessages ?? []).isNotEmpty) LunaButton.text(
|
||||
icon: Icons.messenger_outline_rounded,
|
||||
text: 'Messages',
|
||||
onTap: () async {
|
||||
LunaDialogs().showMessages(
|
||||
context,
|
||||
record.statusMessages.map<String>((status) => status.messages.join('\n')).toList(),
|
||||
);
|
||||
},
|
||||
),
|
||||
if(
|
||||
record?.status == RadarrQueueRecordStatus.COMPLETED &&
|
||||
record?.trackedDownloadStatus == RadarrTrackedDownloadStatus.WARNING &&
|
||||
(record?.outputPath ?? '').isNotEmpty
|
||||
) LunaButton.text(
|
||||
icon: Icons.download_done_rounded,
|
||||
text: 'radarr.Import'.tr(),
|
||||
onTap: () async => RadarrManualImportDetailsRouter().navigateTo(context, path: record.outputPath)
|
||||
),
|
||||
LunaButton.text(
|
||||
icon: Icons.delete_rounded,
|
||||
color: LunaColours.red,
|
||||
text: 'Remove',
|
||||
onTap: () async {
|
||||
if(context.read<RadarrState>().enabled) {
|
||||
bool result = await RadarrDialogs().confirmDeleteQueue(context);
|
||||
if(result) {
|
||||
await context.read<RadarrState>().api.queue.delete(
|
||||
id: record.id,
|
||||
blacklist: RadarrDatabaseValue.QUEUE_BLACKLIST.data,
|
||||
removeFromClient: RadarrDatabaseValue.QUEUE_REMOVE_FROM_CLIENT.data,
|
||||
);
|
||||
context.read<RadarrState>().api.command.refreshMonitoredDownloads()
|
||||
.then((_) => context.read<RadarrState>().fetchQueue());
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,8 @@ class _State extends State<RadarrReleasesAppBarFilterButton> {
|
||||
),
|
||||
),
|
||||
),
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
width: LunaTextInputBar.appBarInnerHeight,
|
||||
margin: EdgeInsets.fromLTRB(0.0, 0.0, 12.0, 14.0),
|
||||
color: Theme.of(context).canvasColor,
|
||||
);
|
||||
|
||||
@@ -61,6 +61,8 @@ class _State extends State<RadarrReleasesAppBarSortButton> {
|
||||
),
|
||||
),
|
||||
),
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
width: LunaTextInputBar.appBarInnerHeight,
|
||||
margin: EdgeInsets.fromLTRB(0.0, 0.0, 12.0, 13.5),
|
||||
color: Theme.of(context).canvasColor,
|
||||
);
|
||||
|
||||
@@ -26,6 +26,8 @@ class _State extends State<SABnzbdHistoryHideButton> {
|
||||
onPressed: () => model.historyHideFailed = !model.historyHideFailed,
|
||||
),
|
||||
),
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
width: LunaTextInputBar.appBarInnerHeight,
|
||||
margin: EdgeInsets.only(left: 12.0),
|
||||
color: Theme.of(context).canvasColor,
|
||||
);
|
||||
|
||||
@@ -70,7 +70,7 @@ class _State extends State<_SettingsConfigurationRoute> with LunaScrollControlle
|
||||
},
|
||||
),
|
||||
),
|
||||
LunaListTile(
|
||||
if(LunaQuickActions.isPlatformCompatible) LunaListTile(
|
||||
context: context,
|
||||
title: LunaText.title(text: 'Quick Actions'),
|
||||
subtitle: LunaText.subtitle(text: 'Quick Actions on the Home Screen'),
|
||||
|
||||
@@ -64,7 +64,7 @@ class _State extends State<_SettingsHomeRoute> with LunaScrollControllerMixin {
|
||||
onTap: () async => SettingsProfilesRouter().navigateTo(context),
|
||||
),
|
||||
LunaDivider(),
|
||||
LunaListTile(
|
||||
if(LunaInAppPurchases.isPlatformCompatible) LunaListTile(
|
||||
context: context,
|
||||
title: LunaText.title(text: 'Donations'),
|
||||
subtitle: LunaText.subtitle(text: 'Donate to the Developer'),
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'package:fluro/fluro.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/settings.dart';
|
||||
import 'package:package_info/package_info.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
class SettingsSystemRouter extends SettingsPageRouter {
|
||||
SettingsSystemRouter() : super('/settings/system');
|
||||
@@ -45,9 +45,9 @@ class _State extends State<_SettingsSystemRoute> with LunaScrollControllerMixin
|
||||
SettingsSystemBackupRestoreBackupTile(),
|
||||
SettingsSystemBackupRestoreRestoreTile(),
|
||||
LunaDivider(),
|
||||
_enableAnalytics(),
|
||||
_enableCrashlytics(),
|
||||
LunaDivider(),
|
||||
if(LunaFirebaseAnalytics.isPlatformCompatible) _enableAnalytics(),
|
||||
if(LunaFirebaseCrashlytics.isPlatformCompatible) _enableCrashlytics(),
|
||||
if(LunaFirebaseCrashlytics.isPlatformCompatible || LunaFirebaseAnalytics.isPlatformCompatible) LunaDivider(),
|
||||
_language(),
|
||||
_clearConfiguration(),
|
||||
],
|
||||
@@ -57,17 +57,18 @@ class _State extends State<_SettingsSystemRoute> with LunaScrollControllerMixin
|
||||
Widget _versionInformation() {
|
||||
return FutureBuilder(
|
||||
future: PackageInfo.fromPlatform(),
|
||||
builder: (context, AsyncSnapshot<PackageInfo> snapshot) => LunaListTile(
|
||||
context: context,
|
||||
title: LunaText.title(
|
||||
text: snapshot.hasData
|
||||
? 'Version: ${snapshot.data.version} (${snapshot.data.buildNumber})'
|
||||
: 'Version: Loading...',
|
||||
),
|
||||
subtitle: LunaText.subtitle(text: 'View Recent Changes'),
|
||||
trailing: LunaIconButton(icon: Icons.system_update),
|
||||
onTap: () async => LunaChangelog().showChangelog(snapshot.data.version, snapshot.data.buildNumber),
|
||||
),
|
||||
builder: (context, AsyncSnapshot<PackageInfo> snapshot) {
|
||||
String version = 'Loading${LunaUI.TEXT_ELLIPSIS}';
|
||||
if(snapshot.hasError) version = 'Unknown';
|
||||
if(snapshot.hasData) version = '${snapshot.data.version} (${snapshot.data.buildNumber})';
|
||||
return LunaListTile(
|
||||
context: context,
|
||||
title: LunaText.title(text: 'Version: $version'),
|
||||
subtitle: LunaText.subtitle(text: 'View Recent Changes'),
|
||||
trailing: LunaIconButton(icon: Icons.system_update),
|
||||
onTap: () async => LunaChangelog().showChangelog(snapshot.data?.version, snapshot.data?.buildNumber),
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ class _State extends State<SonarrQueueQueueTile> {
|
||||
children: [
|
||||
LunaHighlightedNode(
|
||||
text: widget.record?.protocol?.lunaCapitalizeFirstLetters() ?? LunaUI.TEXT_EMDASH,
|
||||
backgroundColor: widget.record.protocol == 'torrent' ? LunaColours.purple : LunaColours.blue,
|
||||
backgroundColor: LunaColours.blue,
|
||||
),
|
||||
LunaHighlightedNode(
|
||||
text: widget.record?.quality?.quality?.name ?? 'Unknown',
|
||||
@@ -167,15 +167,14 @@ class _State extends State<SonarrQueueQueueTile> {
|
||||
text: 'Messages',
|
||||
icon: Icons.messenger_outline_rounded,
|
||||
onTap: () async {
|
||||
String messages = widget.record.statusMessages.fold('', (warnings, status) {
|
||||
warnings += status.messages.fold<String>('', (message, element) => message += '\n${LunaUI.TEXT_BULLET} $element');
|
||||
return warnings.trim();
|
||||
});
|
||||
LunaDialogs().textPreview(context, 'Messages', messages);
|
||||
LunaDialogs().showMessages(
|
||||
context,
|
||||
widget.record.statusMessages.map<String>((status) => status.messages.join('\n')).toList(),
|
||||
);
|
||||
},
|
||||
),
|
||||
LunaButton.text(
|
||||
text: 'Delete',
|
||||
text: 'Remove',
|
||||
icon: Icons.delete_rounded,
|
||||
color: LunaColours.red,
|
||||
onTap: () async => _deleteQueueRecord(),
|
||||
|
||||
@@ -43,6 +43,8 @@ class _State extends State<SonarrReleasesAppBarFilterButton> {
|
||||
),
|
||||
),
|
||||
),
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
width: LunaTextInputBar.appBarInnerHeight,
|
||||
margin: LunaTextInputBar.appBarMargin.subtract(EdgeInsets.only(left: 12.0)),
|
||||
color: Theme.of(context).canvasColor,
|
||||
);
|
||||
|
||||
@@ -60,6 +60,8 @@ class _State extends State<SonarrReleasesAppBarSortButton> {
|
||||
),
|
||||
),
|
||||
),
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
width: LunaTextInputBar.appBarInnerHeight,
|
||||
margin: LunaTextInputBar.appBarMargin.subtract(EdgeInsets.only(left: 12.0)),
|
||||
color: Theme.of(context).canvasColor,
|
||||
);
|
||||
|
||||
@@ -43,6 +43,8 @@ class _State extends State<SonarrSeriesSearchBarFilterButton> {
|
||||
),
|
||||
),
|
||||
),
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
width: LunaTextInputBar.appBarInnerHeight,
|
||||
margin: EdgeInsets.symmetric(horizontal: 12.0),
|
||||
color: Theme.of(context).canvasColor,
|
||||
);
|
||||
|
||||
@@ -60,6 +60,8 @@ class _State extends State<SonarrSeriesSearchBarSortButton> {
|
||||
),
|
||||
),
|
||||
),
|
||||
height: LunaTextInputBar.appBarInnerHeight,
|
||||
width: LunaTextInputBar.appBarInnerHeight,
|
||||
margin: EdgeInsets.zero,
|
||||
color: Theme.of(context).canvasColor,
|
||||
);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"radarr.InCinemasIn": "In Cinemas in {}",
|
||||
"radarr.InCinemasToday": "In Cinemas Today",
|
||||
"radarr.Interactive": "Interactive",
|
||||
"radarr.Language": "Language",
|
||||
"radarr.Languages": "Languages",
|
||||
"radarr.ManualImport": "Manual Import",
|
||||
"radarr.ManualImportDescription": "Import Movies from the Filesystem",
|
||||
|
||||
@@ -13,7 +13,7 @@ import firebase_crashlytics
|
||||
import firebase_messaging
|
||||
import firebase_storage
|
||||
import network_info_plus_macos
|
||||
import package_info
|
||||
import package_info_plus_macos
|
||||
import path_provider_macos
|
||||
import shared_preferences_macos
|
||||
import url_launcher_macos
|
||||
|
||||
@@ -243,7 +243,7 @@ PODS:
|
||||
- Firebase/Storage (7.3.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseStorage (~> 7.3.0)
|
||||
- firebase_auth (1.0.2):
|
||||
- firebase_auth (1.0.3):
|
||||
- Firebase/Auth (~> 7.3.0)
|
||||
- Firebase/CoreOnly (~> 7.3.0)
|
||||
- firebase_core
|
||||
@@ -261,7 +261,7 @@ PODS:
|
||||
- Firebase/Messaging (~> 7.3.0)
|
||||
- firebase_core
|
||||
- FlutterMacOS
|
||||
- firebase_storage (8.0.2):
|
||||
- firebase_storage (8.0.3):
|
||||
- Firebase/CoreOnly (~> 7.3.0)
|
||||
- Firebase/Storage (~> 7.3.0)
|
||||
- firebase_core
|
||||
@@ -372,7 +372,7 @@ PODS:
|
||||
- network_info_plus_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- Reachability
|
||||
- package_info (0.0.1):
|
||||
- package_info_plus_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- path_provider_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
@@ -393,7 +393,7 @@ DEPENDENCIES:
|
||||
- firebase_storage (from `Flutter/ephemeral/.symlinks/plugins/firebase_storage/macos`)
|
||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||
- network_info_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/network_info_plus_macos/macos`)
|
||||
- package_info (from `Flutter/ephemeral/.symlinks/plugins/package_info/macos`)
|
||||
- package_info_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus_macos/macos`)
|
||||
- path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`)
|
||||
- shared_preferences_macos (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos`)
|
||||
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
||||
@@ -441,8 +441,8 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral
|
||||
network_info_plus_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/network_info_plus_macos/macos
|
||||
package_info:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/package_info/macos
|
||||
package_info_plus_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus_macos/macos
|
||||
path_provider_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos
|
||||
shared_preferences_macos:
|
||||
@@ -456,11 +456,11 @@ SPEC CHECKSUMS:
|
||||
cloud_firestore: 2f06cee99ba40ed1ed79792bafa13e5727bcb706
|
||||
connectivity_plus_macos: dbac1dc9b113dfb69a5691831313b1d8ac1c8269
|
||||
Firebase: 26223c695fe322633274198cb19dca8cb7e54416
|
||||
firebase_auth: a17717c1f074d844ed176534dd588537293d7b27
|
||||
firebase_auth: ba042208860f086aead3c50fcacff096262854e8
|
||||
firebase_core: 5c0a84649819db6738f6d159548762a2def9cb50
|
||||
firebase_crashlytics: 748de8459d6b018d3cca37e6ed7f8c2fbd86d4cd
|
||||
firebase_messaging: 044c01f581b49f873a217792b3e2006ba7be8b9f
|
||||
firebase_storage: 42cc28b760954e1a2810565ad0ffccfcd3b3fa49
|
||||
firebase_storage: e0b723ec5030607a97de3f269c6bb7145de3d193
|
||||
FirebaseAuth: c224a0cf1afa0949bd5c7bfcf154b4f5ce8ddef2
|
||||
FirebaseCore: 4d3c72622ce0e2106aaa07bb4b2935ba2c370972
|
||||
FirebaseCoreDiagnostics: d50e11039e5984d92c8a512be2395f13df747350
|
||||
@@ -479,7 +479,7 @@ SPEC CHECKSUMS:
|
||||
leveldb-library: 50c7b45cbd7bf543c81a468fe557a16ae3db8729
|
||||
nanopb: 1bf24dd71191072e120b83dd02d08f3da0d65e53
|
||||
network_info_plus_macos: 38ec4a578ecdfcddab609f61da3026d0b32900e5
|
||||
package_info: 6eba2fd8d3371dda2d85c8db6fe97488f24b74b2
|
||||
package_info_plus_macos: f010621b07802a241d96d01876d6705f15e77c1c
|
||||
path_provider_macos: a0a3fd666cb7cd0448e936fb4abad4052961002b
|
||||
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
|
||||
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
|
||||
|
||||
67
pubspec.lock
67
pubspec.lock
@@ -7,14 +7,14 @@ packages:
|
||||
name: _fe_analyzer_shared
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "19.0.0"
|
||||
version: "20.0.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.4.0"
|
||||
archive:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -343,21 +343,21 @@ packages:
|
||||
name: firebase_auth
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
version: "1.0.3"
|
||||
firebase_auth_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_auth_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.0.1"
|
||||
version: "4.0.2"
|
||||
firebase_auth_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_auth_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
version: "1.0.5"
|
||||
firebase_core:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -420,7 +420,7 @@ packages:
|
||||
name: firebase_storage
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "8.0.2"
|
||||
version: "8.0.3"
|
||||
firebase_storage_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -582,7 +582,7 @@ packages:
|
||||
name: in_app_purchase
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.5.1+2"
|
||||
version: "0.5.1+3"
|
||||
infinite_scroll_pagination:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -709,13 +709,48 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
package_info:
|
||||
package_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: package_info
|
||||
name: package_info_plus
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
version: "1.0.0"
|
||||
package_info_plus_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_info_plus_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
package_info_plus_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_info_plus_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
package_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_info_plus_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
package_info_plus_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_info_plus_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
package_info_plus_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_info_plus_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -855,14 +890,14 @@ packages:
|
||||
name: quiver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.0.1"
|
||||
radarr:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: radarr
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
path: "/Users/jagandeepbrar/Git/Packages/radarr"
|
||||
relative: false
|
||||
source: path
|
||||
version: "2.1.0"
|
||||
share:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1098,7 +1133,7 @@ packages:
|
||||
name: uuid
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
version: "3.0.4"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
20
pubspec.yaml
20
pubspec.yaml
@@ -13,36 +13,38 @@ dependencies:
|
||||
connectivity_plus: ^1.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
convert: ^3.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
dio: ^4.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
easy_localization: ^3.0.0 # ANDROID IOS LINUX MACOS WEB
|
||||
easy_localization: ^3.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
encrypt: ^5.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
expandable: ^5.0.1 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
file_picker: ^3.0.1 # ANDROID IOS WEB
|
||||
firebase_analytics: ^7.1.1 # ANDROID IOS WEB
|
||||
firebase_auth: ^1.0.2 # ANDROID IOS MACOS WEB
|
||||
firebase_auth: ^1.0.3 # ANDROID IOS MACOS WEB
|
||||
firebase_core: ^1.0.3 # ANDROID IOS MACOS WEB
|
||||
firebase_crashlytics: ^2.0.0 # ANDROID IOS MACOS
|
||||
firebase_messaging: ^9.1.1 # ANDROID IOS MACOS WEB
|
||||
firebase_storage: ^8.0.2 # ANDROID IOS MACOS WEB
|
||||
firebase_storage: ^8.0.3 # ANDROID IOS MACOS WEB
|
||||
flash: ^1.5.1 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
fluro: ^2.0.3 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
flutter_spinkit: ^5.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
fl_chart: ^0.35.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
# font_awesome_flutter: # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
# path: vendor/font_awesome_flutter
|
||||
google_nav_bar: ^5.0.3 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
hive: ^2.0.2 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
hive_flutter: ^1.0.0 # ANDROID IOS LINUX MACOS WINDOWS
|
||||
in_app_purchase: ^0.5.1+2 # ANDROID IOS
|
||||
in_app_purchase: ^0.5.1+3 # ANDROID IOS
|
||||
infinite_scroll_pagination: ^3.0.1 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
intl: ^0.17.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
modal_bottom_sheet: ^2.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
network_info_plus: ^1.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
package_info: ^2.0.0 # ANDROID IOS MACOS
|
||||
package_info_plus: ^1.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
path_provider: ^2.0.1 # ANDROID IOS LINUX MACOS WINDOWS
|
||||
percent_indicator: ^3.0.1 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
provider: ^5.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
quick_actions: ^0.6.0 # ANDROID IOS
|
||||
radarr: ^2.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
# radarr:
|
||||
# path: /Users/jagandeepbrar/Git/Packages/radarr
|
||||
# radarr: ^2.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
radarr:
|
||||
path: /Users/jagandeepbrar/Git/Packages/radarr
|
||||
share: ^2.0.1 # ANDROID IOS
|
||||
sonarr: ^2.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
stack_trace: ^1.10.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
@@ -51,7 +53,7 @@ dependencies:
|
||||
tautulli: ^2.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
tuple: ^2.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
url_launcher: ^6.0.3 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
uuid: ^3.0.3 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
uuid: ^3.0.4 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
wake_on_lan: ^2.0.1+1 # ANDROID IOS LINUX MACOS WINDOWS
|
||||
xml: ^5.1.0 # ANDROID IOS LINUX MACOS WEB WINDOWS
|
||||
|
||||
|
||||
12
vendor/font_awesome_flutter/.gitignore
vendored
Executable file
12
vendor/font_awesome_flutter/.gitignore
vendored
Executable file
@@ -0,0 +1,12 @@
|
||||
.DS_Store
|
||||
.atom/
|
||||
.idea
|
||||
.packages
|
||||
.dart_tool/
|
||||
.pub/
|
||||
build/
|
||||
ios/.generated/
|
||||
packages
|
||||
pubspec.lock
|
||||
.flutter-plugins
|
||||
local.properties
|
||||
23
vendor/font_awesome_flutter/LICENSE
vendored
Normal file
23
vendor/font_awesome_flutter/LICENSE
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Brian Egan
|
||||
Font Awesome Icons by @fontawesome - https://fontawesome.com
|
||||
License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
BIN
vendor/font_awesome_flutter/icons.json.gpg
vendored
Normal file
BIN
vendor/font_awesome_flutter/icons.json.gpg
vendored
Normal file
Binary file not shown.
52408
vendor/font_awesome_flutter/lib/font_awesome_flutter.dart
vendored
Normal file
52408
vendor/font_awesome_flutter/lib/font_awesome_flutter.dart
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
vendor/font_awesome_flutter/lib/fonts/fa-brands-400.ttf.gpg
vendored
Normal file
BIN
vendor/font_awesome_flutter/lib/fonts/fa-brands-400.ttf.gpg
vendored
Normal file
Binary file not shown.
BIN
vendor/font_awesome_flutter/lib/fonts/fa-duotone-900.ttf.gpg
vendored
Normal file
BIN
vendor/font_awesome_flutter/lib/fonts/fa-duotone-900.ttf.gpg
vendored
Normal file
Binary file not shown.
BIN
vendor/font_awesome_flutter/lib/fonts/fa-light-300.ttf.gpg
vendored
Normal file
BIN
vendor/font_awesome_flutter/lib/fonts/fa-light-300.ttf.gpg
vendored
Normal file
Binary file not shown.
BIN
vendor/font_awesome_flutter/lib/fonts/fa-regular-400.ttf.gpg
vendored
Normal file
BIN
vendor/font_awesome_flutter/lib/fonts/fa-regular-400.ttf.gpg
vendored
Normal file
Binary file not shown.
BIN
vendor/font_awesome_flutter/lib/fonts/fa-solid-900.ttf.gpg
vendored
Normal file
BIN
vendor/font_awesome_flutter/lib/fonts/fa-solid-900.ttf.gpg
vendored
Normal file
Binary file not shown.
71
vendor/font_awesome_flutter/lib/src/fa_duotone_icon.dart
vendored
Normal file
71
vendor/font_awesome_flutter/lib/src/fa_duotone_icon.dart
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:font_awesome_flutter/src/fa_icon.dart';
|
||||
import 'package:font_awesome_flutter/src/icon_data.dart';
|
||||
|
||||
/// Special icon style which can have two colors
|
||||
class FaDuotoneIcon extends StatelessWidget {
|
||||
/// The icon to display. The available icons are described in
|
||||
/// [FontAwesomeIcons]. Applicable icons start with "duotone".
|
||||
final IconDataDuotone icon;
|
||||
|
||||
/// The font size of the icon.
|
||||
///
|
||||
/// Defaults to the current [IconTheme] size, if any. If there is no
|
||||
/// [IconTheme], or it does not specify an explicit size, then it defaults to
|
||||
/// 24.0.
|
||||
///
|
||||
/// If this [FaIcon] is being placed inside an [IconButton], then use
|
||||
/// [IconButton.iconSize] instead, so that the [IconButton] can make the
|
||||
/// splash area the appropriate size as well. The [IconButton] uses an
|
||||
/// [IconTheme] to pass down the size to the [FaIcon].
|
||||
final double? size;
|
||||
|
||||
/// Color used for the icon's main body
|
||||
final Color? primaryColor;
|
||||
|
||||
/// Color used for the icon's accents
|
||||
final Color? secondaryColor;
|
||||
|
||||
/// Semantic label for the icon.
|
||||
///
|
||||
/// Announced in accessibility modes (e.g TalkBack/VoiceOver).
|
||||
/// This label does not show in the UI.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Semantics.label], which is set to [semanticLabel] in the underlying
|
||||
/// [Semantics] widget.
|
||||
final String? semanticLabel;
|
||||
|
||||
const FaDuotoneIcon(
|
||||
this.icon, {
|
||||
Key? key,
|
||||
this.size,
|
||||
this.primaryColor,
|
||||
this.secondaryColor,
|
||||
this.semanticLabel,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Semantics(
|
||||
label: semanticLabel,
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
FaIcon(
|
||||
icon,
|
||||
size: size,
|
||||
color: primaryColor,
|
||||
key: Key("primaryGlyph"),
|
||||
),
|
||||
FaIcon(
|
||||
icon.secondary,
|
||||
size: size,
|
||||
color: secondaryColor,
|
||||
key: Key("secondaryGlyph"),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
148
vendor/font_awesome_flutter/lib/src/fa_icon.dart
vendored
Normal file
148
vendor/font_awesome_flutter/lib/src/fa_icon.dart
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
|
||||
/// Creates an Icon Widget that works for non-material Icons, such as the
|
||||
/// Font Awesome Icons.
|
||||
///
|
||||
/// The default `Icon` Widget from the Material package assumes all Icons are
|
||||
/// square in size and wraps all Icons in a square SizedBox Widget. Icons from
|
||||
/// the FontAwesome package are often wider than they are tall, which causes
|
||||
/// alignment and cutoff issues.
|
||||
///
|
||||
/// This Widget does not wrap the icons in a fixed square box, which allows the
|
||||
/// icons to render based on their size.
|
||||
class FaIcon extends StatelessWidget {
|
||||
/// Creates an icon.
|
||||
///
|
||||
/// The [size] and [color] default to the value given by the current [IconTheme].
|
||||
const FaIcon(
|
||||
this.icon, {
|
||||
Key? key,
|
||||
this.size,
|
||||
this.color,
|
||||
this.semanticLabel,
|
||||
this.textDirection,
|
||||
}) : assert(icon != null),
|
||||
super(key: key);
|
||||
|
||||
/// The icon to display. The available icons are described in
|
||||
/// [FontAwesomeIcons].
|
||||
final IconData? icon;
|
||||
|
||||
/// The font size of the icon.
|
||||
///
|
||||
/// Defaults to the current [IconTheme] size, if any. If there is no
|
||||
/// [IconTheme], or it does not specify an explicit size, then it defaults to
|
||||
/// 24.0.
|
||||
///
|
||||
/// If this [FaIcon] is being placed inside an [IconButton], then use
|
||||
/// [IconButton.iconSize] instead, so that the [IconButton] can make the
|
||||
/// splash area the appropriate size as well. The [IconButton] uses an
|
||||
/// [IconTheme] to pass down the size to the [FaIcon].
|
||||
final double? size;
|
||||
|
||||
/// The color to use when drawing the icon.
|
||||
///
|
||||
/// Defaults to the current [IconTheme] color, if any.
|
||||
///
|
||||
/// The given color will be adjusted by the opacity of the current
|
||||
/// [IconTheme], if any.
|
||||
final Color? color;
|
||||
|
||||
/// Semantic label for the icon.
|
||||
///
|
||||
/// Announced in accessibility modes (e.g TalkBack/VoiceOver).
|
||||
/// This label does not show in the UI.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Semantics.label], which is set to [semanticLabel] in the underlying
|
||||
/// [Semantics] widget.
|
||||
final String? semanticLabel;
|
||||
|
||||
/// The text direction to use for rendering the icon.
|
||||
///
|
||||
/// If this is null, the ambient [Directionality] is used instead.
|
||||
///
|
||||
/// Some icons follow the reading direction. For example, "back" buttons point
|
||||
/// left in left-to-right environments and right in right-to-left
|
||||
/// environments. Such icons have their [IconData.matchTextDirection] field
|
||||
/// set to true, and the [FaIcon] widget uses the [textDirection] to determine
|
||||
/// the orientation in which to draw the icon.
|
||||
///
|
||||
/// This property has no effect if the [icon]'s [IconData.matchTextDirection]
|
||||
/// field is false, but for consistency a text direction value must always be
|
||||
/// specified, either directly using this property or using [Directionality].
|
||||
final TextDirection? textDirection;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(this.textDirection != null || debugCheckHasDirectionality(context));
|
||||
final TextDirection textDirection =
|
||||
this.textDirection ?? Directionality.of(context);
|
||||
|
||||
final IconThemeData iconTheme = IconTheme.of(context);
|
||||
|
||||
final double? iconSize = size ?? iconTheme.size;
|
||||
|
||||
if (icon == null) {
|
||||
return Semantics(
|
||||
label: semanticLabel,
|
||||
child: SizedBox(width: iconSize, height: iconSize),
|
||||
);
|
||||
}
|
||||
|
||||
final double iconOpacity = iconTheme.opacity ?? 1.0;
|
||||
Color iconColor = color ?? iconTheme.color!;
|
||||
if (iconOpacity != 1.0)
|
||||
iconColor = iconColor.withOpacity(iconColor.opacity * iconOpacity);
|
||||
|
||||
Widget iconWidget = RichText(
|
||||
overflow: TextOverflow.visible, // Never clip.
|
||||
textDirection:
|
||||
textDirection, // Since we already fetched it for the assert...
|
||||
text: TextSpan(
|
||||
text: String.fromCharCode(icon!.codePoint),
|
||||
style: TextStyle(
|
||||
inherit: false,
|
||||
color: iconColor,
|
||||
fontSize: iconSize,
|
||||
fontFamily: icon!.fontFamily,
|
||||
package: icon!.fontPackage,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (icon!.matchTextDirection) {
|
||||
switch (textDirection) {
|
||||
case TextDirection.rtl:
|
||||
iconWidget = Transform(
|
||||
transform: Matrix4.identity()..scale(-1.0, 1.0, 1.0),
|
||||
alignment: Alignment.center,
|
||||
transformHitTests: false,
|
||||
child: iconWidget,
|
||||
);
|
||||
break;
|
||||
case TextDirection.ltr:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Semantics(
|
||||
label: semanticLabel,
|
||||
child: ExcludeSemantics(
|
||||
child: iconWidget,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(
|
||||
IconDataProperty('icon', icon, ifNull: '<empty>', showName: false));
|
||||
properties.add(DoubleProperty('size', size, defaultValue: null));
|
||||
properties.add(ColorProperty('color', color, defaultValue: null));
|
||||
}
|
||||
}
|
||||
85
vendor/font_awesome_flutter/lib/src/icon_data.dart
vendored
Normal file
85
vendor/font_awesome_flutter/lib/src/icon_data.dart
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
library font_awesome_flutter;
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
/// [IconData] for a font awesome brand icon from a code point
|
||||
///
|
||||
/// Code points can be obtained from fontawesome.com
|
||||
class IconDataBrands extends IconData {
|
||||
const IconDataBrands(int codePoint)
|
||||
: super(
|
||||
codePoint,
|
||||
fontFamily: 'FontAwesomeBrands',
|
||||
fontPackage: 'font_awesome_flutter',
|
||||
);
|
||||
}
|
||||
|
||||
/// [IconData] for a font awesome solid icon from a code point
|
||||
///
|
||||
/// Code points can be obtained from fontawesome.com
|
||||
class IconDataSolid extends IconData {
|
||||
const IconDataSolid(int codePoint)
|
||||
: super(
|
||||
codePoint,
|
||||
fontFamily: 'FontAwesomeSolid',
|
||||
fontPackage: 'font_awesome_flutter',
|
||||
);
|
||||
}
|
||||
|
||||
/// [IconData] for a font awesome regular icon from a code point
|
||||
///
|
||||
/// Code points can be obtained from fontawesome.com
|
||||
class IconDataRegular extends IconData {
|
||||
const IconDataRegular(int codePoint)
|
||||
: super(
|
||||
codePoint,
|
||||
fontFamily: 'FontAwesomeRegular',
|
||||
fontPackage: 'font_awesome_flutter',
|
||||
);
|
||||
}
|
||||
|
||||
/// [IconData] for a font awesome light icon from a code point. Only works if
|
||||
/// light icons (font awesome pro) have been installed.
|
||||
///
|
||||
/// Code points can be obtained from fontawesome.com
|
||||
class IconDataLight extends IconData {
|
||||
const IconDataLight(int codePoint)
|
||||
: super(
|
||||
codePoint,
|
||||
fontFamily: 'FontAwesomeLight',
|
||||
fontPackage: 'font_awesome_flutter',
|
||||
);
|
||||
}
|
||||
|
||||
/// [IconData] for a font awesome duotone icon from a code point. Only works if
|
||||
/// duotone icons (font awesome pro) have been installed.
|
||||
///
|
||||
/// Code points can be obtained from fontawesome.com. Each duotone icon consists
|
||||
/// of a primary [codePoint] and a [secondary].
|
||||
class IconDataDuotone extends IconData {
|
||||
/// Secondary glyph of the duotone icon
|
||||
///
|
||||
/// Due to tree-shaking restraints [secondary] cannot be the codepoint itself,
|
||||
/// but has to be an [IconData] object.
|
||||
final IconData? secondary;
|
||||
|
||||
const IconDataDuotone(int codePoint, {this.secondary})
|
||||
: super(
|
||||
codePoint,
|
||||
fontFamily: 'FontAwesomeDuotone',
|
||||
fontPackage: 'font_awesome_flutter',
|
||||
);
|
||||
}
|
||||
|
||||
/// [IconData] for a font awesome thin icon from a code point. Only works if
|
||||
/// thin icons (font awesome pro, v6+) have been installed.
|
||||
///
|
||||
/// Code points can be obtained from fontawesome.com
|
||||
class IconDataThin extends IconData {
|
||||
const IconDataThin(int codePoint)
|
||||
: super(
|
||||
codePoint,
|
||||
fontFamily: 'FontAwesomeThin',
|
||||
fontPackage: 'font_awesome_flutter',
|
||||
);
|
||||
}
|
||||
49
vendor/font_awesome_flutter/pubspec.yaml
vendored
Executable file
49
vendor/font_awesome_flutter/pubspec.yaml
vendored
Executable file
@@ -0,0 +1,49 @@
|
||||
name: font_awesome_flutter
|
||||
description: The Font Awesome Icon pack available as Flutter Icons. Provides 1500 additional icons to use in your apps.
|
||||
maintainer: Michael Spiss (@michaelspiss)
|
||||
homepage: https://github.com/fluttercommunity/font_awesome_flutter
|
||||
version: 9.0.0
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
dev_dependencies:
|
||||
recase: ^4.0.0-nullsafety
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
version: ^2.0.0
|
||||
|
||||
flutter:
|
||||
fonts:
|
||||
- family: FontAwesomeBrands
|
||||
fonts:
|
||||
- asset: lib/fonts/fa-brands-400.ttf
|
||||
weight: 400
|
||||
- family: FontAwesomeRegular
|
||||
fonts:
|
||||
- asset: lib/fonts/fa-regular-400.ttf
|
||||
weight: 400
|
||||
- family: FontAwesomeSolid
|
||||
fonts:
|
||||
- asset: lib/fonts/fa-solid-900.ttf
|
||||
weight: 900
|
||||
# Uncomment the following lines to support pro icons
|
||||
- family: FontAwesomeLight
|
||||
fonts:
|
||||
- asset: lib/fonts/fa-light-300.ttf
|
||||
weight: 300
|
||||
# Leave commented out if you don't own duotone icons
|
||||
- family: FontAwesomeDuotone
|
||||
fonts:
|
||||
- asset: lib/fonts/fa-duotone-900.ttf
|
||||
weight: 900
|
||||
# Thin style is available in font awesome pro 6 and beyond
|
||||
# Leave commented out if you don't own version 6
|
||||
- family: FontAwesomeThin
|
||||
fonts:
|
||||
- asset: lib/fonts/fa-thin-100.ttf
|
||||
weight: 100
|
||||
87
vendor/font_awesome_flutter/tool/generate_example.dart
vendored
Normal file
87
vendor/font_awesome_flutter/tool/generate_example.dart
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:recase/recase.dart';
|
||||
|
||||
const Map<String, String> nameAdjustments = {
|
||||
"500px": "fiveHundredPx",
|
||||
"360-degrees": "threeHundredSixtyDegrees",
|
||||
"1": "one",
|
||||
"2": "two",
|
||||
"3": "three",
|
||||
"4": "four",
|
||||
"5": "five",
|
||||
"6": "six",
|
||||
"7": "seven",
|
||||
"8": "eight",
|
||||
"9": "nine",
|
||||
"0": "zero",
|
||||
};
|
||||
|
||||
void main(List<String> arguments) {
|
||||
var file = new File(arguments.first);
|
||||
|
||||
if (!file.existsSync()) {
|
||||
print('Cannot find the file "${arguments.first}".');
|
||||
}
|
||||
|
||||
var content = file.readAsStringSync();
|
||||
Map<String, dynamic> icons = json.decode(content);
|
||||
|
||||
Map<String, String> iconDefinitions = {};
|
||||
|
||||
for (String iconName in icons.keys) {
|
||||
var icon = icons[iconName];
|
||||
|
||||
// At least one icon does not have a glyph in the font files. This property
|
||||
// is marked with "private": true in icons.json
|
||||
if ((icon as Map<String, dynamic>).containsKey('private') &&
|
||||
icon['private']) continue;
|
||||
|
||||
List<String> styles = (icon['styles'] as List).cast<String>();
|
||||
|
||||
if (styles.length > 1) {
|
||||
if (styles.contains('regular')) {
|
||||
styles.remove('regular');
|
||||
iconDefinitions[iconName] = generateExampleIcon(iconName);
|
||||
}
|
||||
|
||||
for (String style in styles) {
|
||||
String name = '${style}_$iconName';
|
||||
iconDefinitions[name] = generateExampleIcon(name);
|
||||
}
|
||||
} else {
|
||||
iconDefinitions[iconName] = generateExampleIcon(iconName);
|
||||
}
|
||||
}
|
||||
|
||||
List<String> generatedOutput = [
|
||||
'',
|
||||
"import 'package:font_awesome_flutter/font_awesome_flutter.dart';",
|
||||
"import 'package:font_awesome_flutter_example/example_icon.dart';",
|
||||
'',
|
||||
'// THIS FILE IS AUTOMATICALLY GENERATED!',
|
||||
'',
|
||||
'final icons = <ExampleIcon>[',
|
||||
];
|
||||
|
||||
generatedOutput.addAll(iconDefinitions.values);
|
||||
|
||||
generatedOutput.add('];');
|
||||
|
||||
File output = new File('example/lib/icons.dart');
|
||||
output.writeAsStringSync(generatedOutput.join('\n'));
|
||||
}
|
||||
|
||||
String generateExampleIcon(String iconName) {
|
||||
if (nameAdjustments.containsKey(iconName)) {
|
||||
iconName = nameAdjustments[iconName]!;
|
||||
}
|
||||
|
||||
iconName = new ReCase(iconName).camelCase;
|
||||
if (iconName.contains('duotone')) {
|
||||
return " ExampleIcon(null, FontAwesomeIcons.$iconName, '$iconName'),";
|
||||
} else {
|
||||
return " ExampleIcon(FontAwesomeIcons.$iconName, null, '$iconName'),";
|
||||
}
|
||||
}
|
||||
204
vendor/font_awesome_flutter/tool/generate_font.dart
vendored
Normal file
204
vendor/font_awesome_flutter/tool/generate_font.dart
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:recase/recase.dart';
|
||||
import 'package:version/version.dart';
|
||||
|
||||
const Map<String, String> nameAdjustments = {
|
||||
"500px": "fiveHundredPx",
|
||||
"360-degrees": "threeHundredSixtyDegrees",
|
||||
"1": "one",
|
||||
"2": "two",
|
||||
"3": "three",
|
||||
"4": "four",
|
||||
"5": "five",
|
||||
"6": "six",
|
||||
"7": "seven",
|
||||
"8": "eight",
|
||||
"9": "nine",
|
||||
"0": "zero",
|
||||
};
|
||||
|
||||
void main(List<String> arguments) {
|
||||
var file = new File(arguments.first);
|
||||
|
||||
if (!file.existsSync()) {
|
||||
print('Cannot find the file "${arguments.first}".');
|
||||
}
|
||||
|
||||
var content = file.readAsStringSync();
|
||||
Map<String, dynamic> icons = json.decode(content);
|
||||
|
||||
Map<String, String> iconDefinitions = {};
|
||||
|
||||
bool hasDuotone = false;
|
||||
|
||||
// figure out current version
|
||||
Version highestVersion = Version.parse("0.0.0");
|
||||
|
||||
for (String iconName in icons.keys) {
|
||||
var icon = icons[iconName];
|
||||
|
||||
// At least one icon does not have a glyph in the font files. This property
|
||||
// is marked with "private": true in icons.json
|
||||
if ((icon as Map<String, dynamic>).containsKey('private') &&
|
||||
icon['private']) continue;
|
||||
|
||||
// compute highest version
|
||||
var changes = (icon["changes"] as List);
|
||||
|
||||
List<Version> versions = changes.map((v) {
|
||||
// since font awesome does not adhere to semver standards
|
||||
var partsCount = v.split(".").length;
|
||||
if (partsCount == 1) {
|
||||
return v + ".0.0";
|
||||
} else if (partsCount == 2) {
|
||||
return v + ".0";
|
||||
} else if (partsCount == 3) {
|
||||
return v;
|
||||
} else {
|
||||
return "0.0.0";
|
||||
}
|
||||
}).map((v) {
|
||||
try {
|
||||
return Version.parse(v);
|
||||
} on FormatException {
|
||||
return Version.parse("0.0.0");
|
||||
}
|
||||
}).toList(growable: true)
|
||||
..add(highestVersion)
|
||||
..sort();
|
||||
|
||||
highestVersion = versions.last;
|
||||
|
||||
var unicode = icon['unicode'];
|
||||
List<String> styles = (icon['styles'] as List).cast<String>();
|
||||
|
||||
if (styles.length > 1) {
|
||||
if (styles.contains('regular')) {
|
||||
styles.remove('regular');
|
||||
iconDefinitions[iconName] = generateIconDefinition(
|
||||
iconName,
|
||||
'regular',
|
||||
unicode,
|
||||
icon["search"]["terms"],
|
||||
icon["label"],
|
||||
);
|
||||
}
|
||||
|
||||
if (styles.contains('duotone')) {
|
||||
hasDuotone = true;
|
||||
}
|
||||
|
||||
for (String style in styles) {
|
||||
String name = '${style}_$iconName';
|
||||
iconDefinitions[name] = generateIconDefinition(
|
||||
name,
|
||||
style,
|
||||
unicode,
|
||||
icon["search"]["terms"],
|
||||
icon["label"],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
iconDefinitions[iconName] = generateIconDefinition(
|
||||
iconName,
|
||||
styles.first,
|
||||
unicode,
|
||||
icon["search"]["terms"],
|
||||
icon["label"],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
List<String> generatedOutput = [
|
||||
'library font_awesome_flutter;',
|
||||
'',
|
||||
"import 'package:flutter/widgets.dart';",
|
||||
"import 'package:font_awesome_flutter/src/icon_data.dart';",
|
||||
"export 'package:font_awesome_flutter/src/fa_icon.dart';",
|
||||
"export 'package:font_awesome_flutter/src/icon_data.dart';",
|
||||
"export 'package:font_awesome_flutter/src/fa_duotone_icon.dart';",
|
||||
];
|
||||
|
||||
if (hasDuotone) {
|
||||
generatedOutput
|
||||
.add("export 'package:font_awesome_flutter/src/fa_duotone_icon.dart';");
|
||||
}
|
||||
|
||||
generatedOutput.addAll([
|
||||
'',
|
||||
'// THIS FILE IS AUTOMATICALLY GENERATED!',
|
||||
'',
|
||||
'/// Icons based on font awesome $highestVersion',
|
||||
'class FontAwesomeIcons {',
|
||||
]);
|
||||
|
||||
generatedOutput.addAll(iconDefinitions.values);
|
||||
|
||||
generatedOutput.add('}');
|
||||
|
||||
File output = new File('lib/font_awesome_flutter.dart');
|
||||
output.writeAsStringSync(generatedOutput.join('\n'));
|
||||
}
|
||||
|
||||
String generateIconDocumentation(
|
||||
String iconName, String style, List searchTerms, String iconLabel) {
|
||||
searchTerms = searchTerms;
|
||||
var searchTermsString = searchTerms.toString();
|
||||
searchTermsString =
|
||||
searchTermsString.substring(1, searchTermsString.length - 1);
|
||||
|
||||
iconName = iconName.replaceFirst("solid_", "");
|
||||
|
||||
var doc = '/// ${style.sentenceCase} $iconLabel icon\n'
|
||||
'///\n'
|
||||
'/// https://fontawesome.com/icons/$iconName?style=$style';
|
||||
|
||||
if (searchTermsString.length != 0) {
|
||||
doc += '\n/// $searchTermsString';
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
String generateIconDefinition(String iconName, String style, String unicode,
|
||||
List searchTerms, String iconLabel) {
|
||||
if (style == 'duotone') {
|
||||
return generateDuotoneIconDefinition(
|
||||
iconName, unicode, searchTerms, iconLabel);
|
||||
}
|
||||
|
||||
String doc =
|
||||
generateIconDocumentation(iconName, style, searchTerms, iconLabel);
|
||||
|
||||
iconName = normalizeIconName(iconName);
|
||||
String iconDataSource = styleToDataSource(style);
|
||||
|
||||
return '$doc\nstatic const IconData $iconName = const $iconDataSource(0x$unicode);';
|
||||
}
|
||||
|
||||
String generateDuotoneIconDefinition(String iconName, String primaryUnicode,
|
||||
List searchTerms, String iconLabel) {
|
||||
String doc =
|
||||
generateIconDocumentation(iconName, "duotone", searchTerms, iconLabel);
|
||||
|
||||
iconName = normalizeIconName(iconName);
|
||||
String secondaryUnicode = (int.parse(primaryUnicode, radix: 16) + 0x100000)
|
||||
.toRadixString(16)
|
||||
.toString();
|
||||
|
||||
return '$doc\nstatic const IconDataDuotone $iconName = const IconDataDuotone(0x$primaryUnicode, secondary: const IconDataDuotone(0x$secondaryUnicode),);';
|
||||
}
|
||||
|
||||
String normalizeIconName(String iconName) {
|
||||
iconName = nameAdjustments[iconName] ?? iconName;
|
||||
|
||||
return new ReCase(iconName).camelCase;
|
||||
}
|
||||
|
||||
String styleToDataSource(String style) {
|
||||
style = '${style[0].toUpperCase()}${style.substring(1)}';
|
||||
|
||||
return 'IconData$style';
|
||||
}
|
||||
25
vendor/font_awesome_flutter/tool/update.bat
vendored
Normal file
25
vendor/font_awesome_flutter/tool/update.bat
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
@echo off
|
||||
|
||||
if exist icons.json (
|
||||
echo Custom icons.json found, using local data only.
|
||||
|
||||
dart .\tool\generate_font.dart .\icons.json
|
||||
dart .\tool\generate_example.dart .\icons.json
|
||||
) else (
|
||||
echo Updating free icons to newest version.
|
||||
pushd lib\fonts
|
||||
|
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/webfonts/fa-brands-400.ttf', 'fa-brands-400.ttf')"
|
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/webfonts/fa-regular-400.ttf', 'fa-regular-400.ttf')"
|
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/webfonts/fa-solid-900.ttf', 'fa-solid-900.ttf')"
|
||||
|
||||
popd
|
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/metadata/icons.json', 'icons.json')"
|
||||
|
||||
dart .\tool\generate_font.dart .\icons.json
|
||||
dart .\tool\generate_example.dart .\icons.json
|
||||
del "icons.json" /f /q
|
||||
)
|
||||
|
||||
dartfmt -w .\lib\font_awesome_flutter.dart & ^
|
||||
dartfmt -w .\example\lib\icons.dart
|
||||
29
vendor/font_awesome_flutter/tool/update.sh
vendored
Executable file
29
vendor/font_awesome_flutter/tool/update.sh
vendored
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
if [ -e ./icons.json ];
|
||||
then
|
||||
echo "Custom icons.json found, using local data only."
|
||||
|
||||
dart ./tool/generate_font.dart ./icons.json
|
||||
dart ./tool/generate_example.dart ./icons.json
|
||||
dartfmt -w ./lib/font_awesome_flutter.dart
|
||||
dartfmt -w ./example/lib/icons.dart
|
||||
|
||||
else
|
||||
echo "Updating icons to newest version."
|
||||
pushd lib/fonts/
|
||||
|
||||
curl -O -L "https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/webfonts/fa-brands-400.ttf"
|
||||
curl -O -L "https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/webfonts/fa-regular-400.ttf"
|
||||
curl -O -L "https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/webfonts/fa-solid-900.ttf"
|
||||
|
||||
popd
|
||||
|
||||
curl -o /tmp/icons.json "https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/metadata/icons.json"
|
||||
|
||||
dart ./tool/generate_font.dart /tmp/icons.json
|
||||
dart ./tool/generate_example.dart /tmp/icons.json
|
||||
dartfmt -w ./lib/font_awesome_flutter.dart
|
||||
dartfmt -w ./example/lib/icons.dart
|
||||
|
||||
rm /tmp/icons.json
|
||||
fi
|
||||
Reference in New Issue
Block a user