mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-07 13:38:13 -08:00
Web - Add docker image and baseUrl config support (#32)
This commit is contained in:
parent
80a0fdbee4
commit
bfcbf5402d
12 changed files with 144 additions and 138 deletions
25
.dockerignore
Normal file
25
.dockerignore
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
**/.classpath
|
||||
**/.dockerignore
|
||||
**/.env
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/.project
|
||||
**/.settings
|
||||
**/.toolstarget
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/*.*proj.user
|
||||
**/*.dbmdl
|
||||
**/*.jfm
|
||||
**/bin
|
||||
**/charts
|
||||
**/docker-compose*
|
||||
**/compose*
|
||||
**/Dockerfile*
|
||||
**/node_modules
|
||||
**/npm-debug.log
|
||||
**/obj
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
LICENSE
|
||||
README.md
|
||||
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
|
|
@ -278,3 +278,11 @@ jobs:
|
|||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }} # Automatically provided by GitHub Actions
|
||||
publish_dir: ./build/web
|
||||
|
||||
- name: Deploy to ghcr.io
|
||||
uses: mr-smithers-excellent/docker-build-push@v6
|
||||
with:
|
||||
image: fladder
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
|||
12
.metadata
12
.metadata
|
|
@ -4,7 +4,7 @@
|
|||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: "2f708eb8396e362e280fac22cf171c2cb467343c"
|
||||
revision: "2663184aa79047d0a33a14a3b607954f8fdd8730"
|
||||
channel: "stable"
|
||||
|
||||
project_type: app
|
||||
|
|
@ -13,11 +13,11 @@ project_type: app
|
|||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
|
||||
base_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
|
||||
- platform: android
|
||||
create_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
|
||||
base_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
|
||||
create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
- platform: web
|
||||
create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
|
||||
# User provided section
|
||||
|
||||
|
|
|
|||
11
Dockerfile
Normal file
11
Dockerfile
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
FROM nginx:alpine
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
ENV BASE_URL=""
|
||||
|
||||
COPY build/web /usr/share/nginx/html
|
||||
|
||||
RUN echo '{"baseUrl": "${BASE_URL}"}' > /usr/share/nginx/html/assets/config/config.json
|
||||
|
||||
CMD /bin/sh -c 'sed -i "s|\${BASE_URL}|${BASE_URL}|g" /usr/share/nginx/html/assets/config/config.json && nginx -g "daemon off;"'
|
||||
3
config/config.json
Normal file
3
config/config.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"baseUrl": null
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'package:fladder/providers/shared_provider.dart';
|
||||
import 'package:fladder/util/application_info.dart';
|
||||
import 'package:fladder/util/string_extensions.dart';
|
||||
|
||||
void main() async {
|
||||
_setupLogging();
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
MediaKit.ensureInitialized();
|
||||
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
|
||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
|
||||
runApp(
|
||||
ProviderScope(
|
||||
overrides: [
|
||||
sharedPreferencesProvider.overrideWith((ref) => sharedPreferences),
|
||||
applicationInfoProvider.overrideWith(
|
||||
(ref) => ApplicationInfo(
|
||||
name: packageInfo.appName,
|
||||
buildNumber: packageInfo.buildNumber,
|
||||
version: packageInfo.version,
|
||||
os: defaultTargetPlatform.name.capitalize(),
|
||||
),
|
||||
),
|
||||
],
|
||||
child: const Main(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _setupLogging() {
|
||||
Logger.root.level = Level.ALL;
|
||||
Logger.root.onRecord.listen((rec) {
|
||||
if (kDebugMode) {
|
||||
print('${rec.level.name}: ${rec.time}: ${rec.message}');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
class Main extends ConsumerWidget {
|
||||
const Main({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return const MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Center(child: Text("AndroidTV")),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
import 'dart:ui';
|
||||
|
||||
|
|
@ -32,6 +34,7 @@ import 'package:fladder/screens/login/lock_screen.dart';
|
|||
import 'package:fladder/theme.dart';
|
||||
import 'package:fladder/util/adaptive_layout.dart';
|
||||
import 'package:fladder/util/application_info.dart';
|
||||
import 'package:fladder/util/fladder_config.dart';
|
||||
import 'package:fladder/util/string_extensions.dart';
|
||||
import 'package:fladder/util/themes_data.dart';
|
||||
|
||||
|
|
@ -57,14 +60,24 @@ class CustomCacheManager {
|
|||
);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> loadConfig() async {
|
||||
final configString = await rootBundle.loadString('config/config.json');
|
||||
return jsonDecode(configString);
|
||||
}
|
||||
|
||||
void main() async {
|
||||
if (kIsWeb) {
|
||||
html.document.onContextMenu.listen((event) => event.preventDefault());
|
||||
}
|
||||
_setupLogging();
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
MediaKit.ensureInitialized();
|
||||
|
||||
if (kIsWeb) {
|
||||
html.document.onContextMenu.listen((event) => event.preventDefault());
|
||||
final result = await loadConfig();
|
||||
log(result.toString());
|
||||
FladderConfig.fromJson(result);
|
||||
log(FladderConfig.baseUrl.toString());
|
||||
}
|
||||
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
|
||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:ficonsax/ficonsax.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import 'package:fladder/models/account_model.dart';
|
||||
import 'package:fladder/providers/auth_provider.dart';
|
||||
import 'package:fladder/providers/shared_provider.dart';
|
||||
import 'package:fladder/util/list_padding.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class LoginEditUser extends ConsumerWidget {
|
||||
final AccountModel user;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import 'package:fladder/screens/shared/outlined_text_field.dart';
|
|||
import 'package:fladder/screens/shared/passcode_input.dart';
|
||||
import 'package:fladder/util/adaptive_layout.dart';
|
||||
import 'package:fladder/util/auth_service.dart';
|
||||
import 'package:fladder/util/fladder_config.dart';
|
||||
import 'package:fladder/util/list_padding.dart';
|
||||
import 'package:fladder/util/localization_helper.dart';
|
||||
import 'package:fladder/util/string_extensions.dart';
|
||||
|
|
@ -43,7 +44,7 @@ class _LoginPageState extends ConsumerState<LoginScreen> {
|
|||
bool startCheckingForErrors = false;
|
||||
bool addingNewUser = false;
|
||||
bool editingUsers = false;
|
||||
late final TextEditingController serverTextController = TextEditingController(text: "");
|
||||
late final TextEditingController serverTextController = TextEditingController(text: '');
|
||||
|
||||
final usernameController = TextEditingController();
|
||||
final passwordController = TextEditingController();
|
||||
|
|
@ -64,6 +65,11 @@ class _LoginPageState extends ConsumerState<LoginScreen> {
|
|||
final currentAccounts = ref.read(authProvider.notifier).getSavedAccounts();
|
||||
addingNewUser = currentAccounts.isEmpty;
|
||||
ref.read(lockScreenActiveProvider.notifier).update((state) => true);
|
||||
if (FladderConfig.baseUrl != null) {
|
||||
serverTextController.text = FladderConfig.baseUrl!;
|
||||
_parseUrl(FladderConfig.baseUrl!);
|
||||
retrieveListOfUsers();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -258,7 +264,7 @@ class _LoginPageState extends ConsumerState<LoginScreen> {
|
|||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (accounts.isNotEmpty)
|
||||
|
|
@ -282,33 +288,35 @@ class _LoginPageState extends ConsumerState<LoginScreen> {
|
|||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: OutlinedTextField(
|
||||
controller: serverTextController,
|
||||
onChanged: _parseUrl,
|
||||
onSubmitted: (value) => retrieveListOfUsers(),
|
||||
autoFillHints: const [AutofillHints.url],
|
||||
keyboardType: TextInputType.url,
|
||||
textInputAction: TextInputAction.go,
|
||||
label: context.localized.server,
|
||||
errorText: (invalidUrl == null || serverTextController.text.isEmpty || !startCheckingForErrors)
|
||||
? null
|
||||
: invalidUrl,
|
||||
if (FladderConfig.baseUrl == null) ...[
|
||||
Flexible(
|
||||
child: OutlinedTextField(
|
||||
controller: serverTextController,
|
||||
onChanged: _parseUrl,
|
||||
onSubmitted: (value) => retrieveListOfUsers(),
|
||||
autoFillHints: const [AutofillHints.url],
|
||||
keyboardType: TextInputType.url,
|
||||
textInputAction: TextInputAction.go,
|
||||
label: context.localized.server,
|
||||
errorText: (invalidUrl == null || serverTextController.text.isEmpty || !startCheckingForErrors)
|
||||
? null
|
||||
: invalidUrl,
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Tooltip(
|
||||
message: context.localized.retrievePublicListOfUsers,
|
||||
waitDuration: const Duration(seconds: 1),
|
||||
child: IconButton.filled(
|
||||
onPressed: () => retrieveListOfUsers(),
|
||||
icon: const Icon(
|
||||
IconsaxOutline.refresh,
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Tooltip(
|
||||
message: context.localized.retrievePublicListOfUsers,
|
||||
waitDuration: const Duration(seconds: 1),
|
||||
child: IconButton.filled(
|
||||
onPressed: () => retrieveListOfUsers(),
|
||||
icon: const Icon(
|
||||
IconsaxOutline.refresh,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
AnimatedFadeSize(
|
||||
|
|
|
|||
17
lib/util/fladder_config.dart
Normal file
17
lib/util/fladder_config.dart
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
class FladderConfig {
|
||||
static FladderConfig _instance = FladderConfig._();
|
||||
FladderConfig._();
|
||||
|
||||
static String? get baseUrl => _instance._baseUrl;
|
||||
static set baseUrl(String? value) => _instance._baseUrl = value;
|
||||
String? _baseUrl;
|
||||
|
||||
static void fromJson(Map<String, dynamic> json) => _instance = FladderConfig._fromJson(json);
|
||||
|
||||
factory FladderConfig._fromJson(Map<String, dynamic> json) {
|
||||
final config = FladderConfig._();
|
||||
final newUrl = json['baseUrl'] as String?;
|
||||
config._baseUrl = newUrl?.isEmpty == true ? null : newUrl;
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
|
@ -159,6 +159,7 @@ flutter:
|
|||
assets:
|
||||
- icons/
|
||||
- assets/fonts/
|
||||
- config/
|
||||
|
||||
fonts:
|
||||
- family: mp-font
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
<head>
|
||||
<!--
|
||||
If you are serving your web app in a path other than the root, change the
|
||||
href value below to reflect the base path you are serving from.
|
||||
|
||||
|
|
@ -14,46 +14,25 @@
|
|||
This is a placeholder for base href that will be replaced by the value of
|
||||
the `--base-href` argument provided to `flutter build`.
|
||||
-->
|
||||
<base href="$FLUTTER_BASE_HREF" />
|
||||
<base href="$FLUTTER_BASE_HREF">
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible" />
|
||||
<meta name="description" content="A simple cross-platform Jellyfin client." />
|
||||
<meta charset="UTF-8" />
|
||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible" />
|
||||
<meta name="description" content="A simple cross-platform Jellyfin client." />
|
||||
|
||||
<!-- iOS meta tags & icons -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
||||
<meta name="apple-mobile-web-app-title" content="fladder" />
|
||||
<link rel="apple-touch-icon" href="icons/Icon-192.png" />
|
||||
<!-- iOS meta tags & icons -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="fladder">
|
||||
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||
|
||||
<title>fladder</title>
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
|
||||
<script>
|
||||
// The value below is injected by flutter build, do not touch.
|
||||
var serviceWorkerVersion = null;
|
||||
</script>
|
||||
<!-- This script adds the flutter initialization JS code -->
|
||||
<script src="flutter.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
window.addEventListener("load", function (ev) {
|
||||
// Download main.dart.js
|
||||
_flutter.loader.loadEntrypoint({
|
||||
serviceWorker: {
|
||||
serviceWorkerVersion: serviceWorkerVersion,
|
||||
},
|
||||
onEntrypointLoaded: function (engineInitializer) {
|
||||
engineInitializer.initializeEngine().then(function (appRunner) {
|
||||
appRunner.runApp();
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
<title>Fladder</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
</head>
|
||||
<body>
|
||||
<script src="flutter_bootstrap.js" async></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue