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:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }} # Automatically provided by GitHub Actions
|
github_token: ${{ secrets.GITHUB_TOKEN }} # Automatically provided by GitHub Actions
|
||||||
publish_dir: ./build/web
|
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.
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
version:
|
version:
|
||||||
revision: "2f708eb8396e362e280fac22cf171c2cb467343c"
|
revision: "2663184aa79047d0a33a14a3b607954f8fdd8730"
|
||||||
channel: "stable"
|
channel: "stable"
|
||||||
|
|
||||||
project_type: app
|
project_type: app
|
||||||
|
|
@ -13,11 +13,11 @@ project_type: app
|
||||||
migration:
|
migration:
|
||||||
platforms:
|
platforms:
|
||||||
- platform: root
|
- platform: root
|
||||||
create_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
|
create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||||
base_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
|
base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||||
- platform: android
|
- platform: web
|
||||||
create_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
|
create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||||
base_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
|
base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||||
|
|
||||||
# User provided section
|
# 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:io';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
|
|
@ -32,6 +34,7 @@ import 'package:fladder/screens/login/lock_screen.dart';
|
||||||
import 'package:fladder/theme.dart';
|
import 'package:fladder/theme.dart';
|
||||||
import 'package:fladder/util/adaptive_layout.dart';
|
import 'package:fladder/util/adaptive_layout.dart';
|
||||||
import 'package:fladder/util/application_info.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/string_extensions.dart';
|
||||||
import 'package:fladder/util/themes_data.dart';
|
import 'package:fladder/util/themes_data.dart';
|
||||||
|
|
||||||
|
|
@ -57,14 +60,24 @@ class CustomCacheManager {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() async {
|
Future<Map<String, dynamic>> loadConfig() async {
|
||||||
if (kIsWeb) {
|
final configString = await rootBundle.loadString('config/config.json');
|
||||||
html.document.onContextMenu.listen((event) => event.preventDefault());
|
return jsonDecode(configString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void main() async {
|
||||||
_setupLogging();
|
_setupLogging();
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
MediaKit.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();
|
final sharedPreferences = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:ficonsax/ficonsax.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/models/account_model.dart';
|
||||||
import 'package:fladder/providers/auth_provider.dart';
|
import 'package:fladder/providers/auth_provider.dart';
|
||||||
import 'package:fladder/providers/shared_provider.dart';
|
import 'package:fladder/providers/shared_provider.dart';
|
||||||
import 'package:fladder/util/list_padding.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 {
|
class LoginEditUser extends ConsumerWidget {
|
||||||
final AccountModel user;
|
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/screens/shared/passcode_input.dart';
|
||||||
import 'package:fladder/util/adaptive_layout.dart';
|
import 'package:fladder/util/adaptive_layout.dart';
|
||||||
import 'package:fladder/util/auth_service.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/list_padding.dart';
|
||||||
import 'package:fladder/util/localization_helper.dart';
|
import 'package:fladder/util/localization_helper.dart';
|
||||||
import 'package:fladder/util/string_extensions.dart';
|
import 'package:fladder/util/string_extensions.dart';
|
||||||
|
|
@ -43,7 +44,7 @@ class _LoginPageState extends ConsumerState<LoginScreen> {
|
||||||
bool startCheckingForErrors = false;
|
bool startCheckingForErrors = false;
|
||||||
bool addingNewUser = false;
|
bool addingNewUser = false;
|
||||||
bool editingUsers = false;
|
bool editingUsers = false;
|
||||||
late final TextEditingController serverTextController = TextEditingController(text: "");
|
late final TextEditingController serverTextController = TextEditingController(text: '');
|
||||||
|
|
||||||
final usernameController = TextEditingController();
|
final usernameController = TextEditingController();
|
||||||
final passwordController = TextEditingController();
|
final passwordController = TextEditingController();
|
||||||
|
|
@ -64,6 +65,11 @@ class _LoginPageState extends ConsumerState<LoginScreen> {
|
||||||
final currentAccounts = ref.read(authProvider.notifier).getSavedAccounts();
|
final currentAccounts = ref.read(authProvider.notifier).getSavedAccounts();
|
||||||
addingNewUser = currentAccounts.isEmpty;
|
addingNewUser = currentAccounts.isEmpty;
|
||||||
ref.read(lockScreenActiveProvider.notifier).update((state) => true);
|
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(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
if (accounts.isNotEmpty)
|
if (accounts.isNotEmpty)
|
||||||
|
|
@ -282,6 +288,7 @@ class _LoginPageState extends ConsumerState<LoginScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (FladderConfig.baseUrl == null) ...[
|
||||||
Flexible(
|
Flexible(
|
||||||
child: OutlinedTextField(
|
child: OutlinedTextField(
|
||||||
controller: serverTextController,
|
controller: serverTextController,
|
||||||
|
|
@ -310,6 +317,7 @@ class _LoginPageState extends ConsumerState<LoginScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
],
|
||||||
),
|
),
|
||||||
AnimatedFadeSize(
|
AnimatedFadeSize(
|
||||||
child: invalidUrl == null
|
child: invalidUrl == null
|
||||||
|
|
|
||||||
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:
|
assets:
|
||||||
- icons/
|
- icons/
|
||||||
- assets/fonts/
|
- assets/fonts/
|
||||||
|
- config/
|
||||||
|
|
||||||
fonts:
|
fonts:
|
||||||
- family: mp-font
|
- family: mp-font
|
||||||
|
|
|
||||||
|
|
@ -14,46 +14,25 @@
|
||||||
This is a placeholder for base href that will be replaced by the value of
|
This is a placeholder for base href that will be replaced by the value of
|
||||||
the `--base-href` argument provided to `flutter build`.
|
the `--base-href` argument provided to `flutter build`.
|
||||||
-->
|
-->
|
||||||
<base href="$FLUTTER_BASE_HREF" />
|
<base href="$FLUTTER_BASE_HREF">
|
||||||
|
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible" />
|
<meta content="IE=Edge" http-equiv="X-UA-Compatible" />
|
||||||
<meta name="description" content="A simple cross-platform Jellyfin client." />
|
<meta name="description" content="A simple cross-platform Jellyfin client." />
|
||||||
|
|
||||||
<!-- iOS meta tags & icons -->
|
<!-- iOS meta tags & icons -->
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
<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-status-bar-style" content="black">
|
||||||
<meta name="apple-mobile-web-app-title" content="fladder" />
|
<meta name="apple-mobile-web-app-title" content="fladder">
|
||||||
<link rel="apple-touch-icon" href="icons/Icon-192.png" />
|
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||||
|
|
||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
<link rel="icon" type="image/png" href="favicon.png"/>
|
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||||
|
|
||||||
<title>fladder</title>
|
<title>Fladder</title>
|
||||||
<link rel="manifest" href="manifest.json" />
|
<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>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script src="flutter_bootstrap.js" async></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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue