(feat): Implemented Overseerr core architecture, Added platform checks for Firebase, Added module flagging (#425)

This commit is contained in:
Jagandeep Brar
2021-04-13 22:07:14 -05:00
committed by GitHub
parent e7181e70cc
commit e54e4eecec
47 changed files with 739 additions and 99 deletions

View File

@@ -0,0 +1,5 @@
export 'core/database.dart';
export 'core/dialogs.dart';
export 'core/router.dart';
export 'core/state.dart';
export 'core/webhooks.dart';

View File

@@ -0,0 +1,72 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
class OverseerrDatabase extends LunaModuleDatabase {
@override
void registerAdapters() {}
@override
Map<String, dynamic> export() {
Map<String, dynamic> data = {};
for(OverseerrDatabaseValue value in OverseerrDatabaseValue.values) {
switch(value) {
// Primitive values
case OverseerrDatabaseValue.NAVIGATION_INDEX: data[value.key] = value.data; break;
}
}
return data;
}
@override
void import(Map<String, dynamic> config) {
for(String key in config.keys) {
OverseerrDatabaseValue value = valueFromKey(key);
if(value != null) switch(value) {
// Primitive values
case OverseerrDatabaseValue.NAVIGATION_INDEX: value.put(config[key]); break;
}
}
}
@override
OverseerrDatabaseValue valueFromKey(String key) {
switch(key) {
case 'OVERSEERR_NAVIGATION_INDEX': return OverseerrDatabaseValue.NAVIGATION_INDEX;
default: return null;
}
}
}
enum OverseerrDatabaseValue {
NAVIGATION_INDEX,
}
extension OverseerrDatabaseValueExtension on OverseerrDatabaseValue {
String get key {
switch(this) {
case OverseerrDatabaseValue.NAVIGATION_INDEX: return 'OVERSEERR_NAVIGATION_INDEX';
}
throw Exception('Invalid OverseerrDatabaseValue instance');
}
dynamic get data {
final _box = Database.lunaSeaBox;
switch(this) {
case OverseerrDatabaseValue.NAVIGATION_INDEX: return _box.get(this.key, defaultValue: 0);
}
throw Exception('Invalid OverseerrDatabaseValue instance');
}
void put(dynamic value) {
final box = Database.lunaSeaBox;
switch(this) {
case OverseerrDatabaseValue.NAVIGATION_INDEX: if(value is int) box.put(this.key, value); return;
}
LunaLogger().warning('OverseerrDatabaseValueExtension', 'put', 'Attempted to enter data for invalid OverseerrDatabaseValue: ${this?.toString() ?? 'null'}');
}
ValueListenableBuilder listen({ @required Widget Function(BuildContext, dynamic, Widget) builder }) => ValueListenableBuilder(
valueListenable: Database.lunaSeaBox.listenable(keys: [this.key]),
builder: builder,
);
}

View File

@@ -0,0 +1,3 @@
class OverseerrDialogs {
}

View File

@@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/overseerr.dart';
class OverseerrRouter extends LunaModuleRouter {
@override
void defineAllRoutes(FluroRouter router) {
OverseerrHomeRouter().defineRoute(router);
}
}
abstract class OverseerrPageRouter extends LunaPageRouter {
OverseerrPageRouter(String route) : super(route);
@override
void noParameterRouteDefinition(FluroRouter router, Widget widget, { bool homeRoute = false }) => router.define(
fullRoute,
handler: Handler(handlerFunc: (context, params) {
if(!homeRoute && !context.read<OverseerrState>().enabled) return LunaNotEnabledRoute(module: 'Overseerr');
return widget;
}),
transitionType: LunaRouter.transitionType,
);
@override
void withParameterRouteDefinition(
FluroRouter router,
Widget Function(BuildContext, Map<String, List<String>>) handlerFunc,
{ bool homeRoute = false }
) => router.define(
fullRoute,
handler: Handler(handlerFunc: (context, params) {
if(!homeRoute && !context.read<OverseerrState>().enabled) return LunaNotEnabledRoute(module: 'Overseerr');
return handlerFunc(context, params);
}),
transitionType: LunaRouter.transitionType,
);
}

View File

@@ -0,0 +1,53 @@
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/overseerr.dart';
class OverseerrState extends LunaModuleState {
OverseerrState() {
reset();
}
@override
void reset() {
resetProfile();
}
///////////////
/// PROFILE ///
///////////////
/// API handler instance
Overseerr _api;
Overseerr get api => _api;
/// Is the API enabled?
bool _enabled;
bool get enabled => _enabled;
/// Overseerr host
String _host;
String get host => _host;
/// Overseerr API key
String _apiKey;
String get apiKey => _apiKey;
/// Headers to attach to all requests
Map<dynamic, dynamic> _headers;
Map<dynamic, dynamic> get headers => _headers;
/// Reset the profile data, reinitializes API instance
void resetProfile() {
ProfileHiveObject _profile = Database.currentProfileObject;
// Copy profile into state
_enabled = _profile.overseerrEnabled ?? false;
_host = _profile.overseerrHost ?? '';
_apiKey = _profile.overseerrKey ?? '';
_headers = _profile.overseerrHeaders ?? {};
// Create the API instance if Overseerr is enabled
_api = !_enabled ? null : Overseerr(
host: _host,
apiKey: _apiKey,
headers: Map<String, dynamic>.from(_headers),
);
}
}

View File

@@ -0,0 +1,12 @@
import 'package:lunasea/core.dart';
class OverseerrWebhooks extends LunaWebhooks {
@override
Future<void> handle(Map<dynamic, dynamic> data) async {
LunaLogger().warning(
'OverseerrWebhooks',
'handle',
'Unknown event type: ${data['event'] ?? 'null'}',
);
}
}

View File

@@ -0,0 +1 @@
export 'routes/overseerr.dart';

View File

@@ -0,0 +1,2 @@
export 'overseerr/route.dart';
export 'overseerr/widgets.dart';

View File

@@ -0,0 +1,81 @@
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/overseerr.dart';
class OverseerrHomeRouter extends OverseerrPageRouter {
OverseerrHomeRouter() : super('/overseerr');
@override
void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _OverseerrHomeRoute(), homeRoute: true);
}
class _OverseerrHomeRoute extends StatefulWidget {
@override
State<_OverseerrHomeRoute> createState() => _State();
}
class _State extends State<_OverseerrHomeRoute> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
LunaPageController _pageController;
@override
void initState() {
super.initState();
_pageController = LunaPageController(initialPage: OverseerrDatabaseValue.NAVIGATION_INDEX.data);
}
@override
Widget build(BuildContext context) {
return LunaScaffold(
scaffoldKey: _scaffoldKey,
drawer: _drawer(),
appBar: _appBar(),
bottomNavigationBar: _bottomNavigationBar(),
body: _body(),
);
}
Widget _drawer() => LunaDrawer(page: LunaModule.OVERSEERR.key);
Widget _bottomNavigationBar() {
if(context.read<OverseerrState>().enabled) return OverseerrNavigationBar(pageController: _pageController);
return null;
}
Widget _appBar() {
List<String> profiles = Database.profilesBox.keys.fold([], (value, element) {
if(Database.profilesBox.get(element)?.overseerrEnabled ?? false) value.add(element);
return value;
});
List<Widget> actions;
if(context.watch<OverseerrState>().enabled) actions = [];
return LunaAppBar.dropdown(
title: LunaModule.OVERSEERR.name,
useDrawer: true,
profiles: profiles,
actions: actions,
pageController: _pageController,
scrollControllers: OverseerrNavigationBar.scrollControllers,
);
}
Widget _body() {
return Selector<OverseerrState, bool>(
selector: (_, state) => state.enabled,
builder: (context, enabled, _) {
if(!enabled) return LunaMessage.moduleNotEnabled(context: context, module: 'Overseerr');
return PageView(
controller: _pageController,
children: [
LunaMessage(
text: 'Coming Soon',
buttonText: 'Go to Dashboard',
onTap: LunaModule.DASHBOARD.launch,
),
],
);
}
);
}
}

View File

@@ -0,0 +1 @@
export 'widgets/navigation_bar.dart';

View File

@@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
class OverseerrNavigationBar extends StatelessWidget {
final PageController pageController;
static List<ScrollController> scrollControllers = List.generate(icons.length, (_) => ScrollController());
static const List<IconData> icons = [
LunaIcons.movies,
];
static List<String> get titles => [
'Requests',
];
OverseerrNavigationBar({
Key key,
@required this.pageController,
}): super(key: key);
@override
Widget build(BuildContext context) {
return LunaBottomNavigationBar(
pageController: pageController,
scrollControllers: scrollControllers,
icons: icons,
titles: titles,
);
}
}