77 Commits

Author SHA1 Message Date
Jagandeep Brar
64d66c9f74 release: v10.1.0
[skip ci]
2022-08-21 11:49:45 -04:00
Jagandeep Brar
8092ea29ef release(testflight): candidate
[skip ci]
2022-08-20 23:29:54 -04:00
Jagandeep Brar
1cdc551318 release(testflight): beta
[skip ci]
2022-08-20 22:58:24 -04:00
Jagandeep Brar
758756fcf2 fix(database): detect and recover from database corruption 2022-08-20 21:51:16 -04:00
Jagandeep Brar
1b143bc3a1 release(testflight): candidate
[skip ci]
2022-08-18 19:34:09 -04:00
Jagandeep Brar
5a64b4348e release(testflight): beta
[skip ci]
2022-08-18 13:22:16 -04:00
Jagandeep Brar
850d77b08b chore(ci): update TestFlight build commit message format
[skip ci]
2022-08-18 13:21:47 -04:00
Jagandeep Brar
bb553c5c03 chore(ci): update release commit message format
[skip ci]
2022-08-18 13:16:10 -04:00
Jagandeep Brar
350afbf65a release: edge [skip ci] 2022-08-18 13:12:26 -04:00
Jagandeep Brar
e3b4fd5b49 chore(contributors): add @KevoM and @rogeriomendes for translations
[skip ci]
2022-08-18 13:09:56 -04:00
Weblate (bot)
0e1d6ad49d chore: translations update from Hosted Weblate (#686)
[skip ci]

Co-authored-by: Rogério Mendes <rogeriomendes.mg@gmail.com>
Co-authored-by: Maxime Leroy <lisacintosh@gmail.com>
Co-authored-by: punchy <michael@maldonado.tech>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: KevoM <lilmarsu@gmail.com>
Co-authored-by: 愿你多年归来仍是少年 <onestime@126.com>
2022-08-18 13:06:33 -04:00
Jagandeep Brar
f1dcd0c36d fix(database): safely type indexer fields and headers 2022-08-16 20:00:07 -04:00
Jagandeep Brar
450be7290b docs: do not assign group IDs to tabs
[skip ci]
2022-08-16 13:53:58 -04:00
natiz
136b92b8a7 fix(overseerr): issues/requests list view translation keys 2022-08-16 13:36:13 -04:00
Jagandeep Brar
008a849e74 release: candidate [skip ci] 2022-08-15 16:39:21 -04:00
Jagandeep Brar
7e52f64984 release: beta [skip ci] 2022-08-15 15:41:10 -04:00
Jagandeep Brar
2f60cb896a chore(contributors): add @natiz for code contribution
[skip ci]
2022-08-14 13:25:48 -04:00
natiz
b5bb300046 fix(sonarr): fanart image requests not including headers 2022-08-14 13:23:30 -04:00
Jagandeep Brar
a501132448 release: beta [skip ci] 2022-08-14 13:20:21 -04:00
Jagandeep Brar
9e37b6bdad chore(release): do not include release commits in changelog history
[skip ci]
2022-08-14 13:17:33 -04:00
Jagandeep Brar
735e5e763a chore: upgrade to Flutter 3.0.5/e85ea0e79c 2022-08-12 18:02:24 -04:00
Jagandeep Brar
9f9c0fdfb7 chore(flutter): upgrade packages
[skip ci]
2022-08-06 03:15:19 -04:00
Jagandeep Brar
ad22820d66 fix(lidarr): (history) sort list by date descending
[skip ci]
2022-08-06 03:04:54 -04:00
Jagandeep Brar
b55f625d2e docs: add reference to Homebrew Cask releases for macOS
[skip ci]
2022-07-12 12:37:20 -04:00
Jagandeep Brar
a4c52c5eea chore(release): beta release
[skip ci]
2022-07-12 12:31:34 -04:00
Jagandeep Brar
2ababbd1b3 fix(changelog): group changelog item rows by key feature change 2022-07-11 22:36:58 -04:00
Jagandeep Brar
2367050a66 refactor(changelog): do not show documentation changes in in-app changelog 2022-07-09 20:37:29 -04:00
Jagandeep Brar
22bf728a3d fix(radarr): (queue) allow loading queue list when associated movie is not found 2022-07-09 20:33:20 -04:00
Jagandeep Brar
dab455600d chore(ci): remove changelog from Discord notifications
[skip ci]
2022-07-09 18:15:49 -04:00
Jagandeep Brar
a101a70d14 chore(ci): correctly tag Docker images 2022-07-09 16:46:11 -04:00
Jagandeep Brar
c3be1c5ab7 chore: upgrade to Flutter 3.0.4/6ba2af10bb 2022-07-09 16:28:07 -04:00
Jagandeep Brar
c91ba2ce81 fix(android): correctly handle back-button to open drawer on applicable routes 2022-07-09 16:18:21 -04:00
Jagandeep Brar
df65f53a4b feat(changelog): prepare and show changelog on pre-release builds 2022-07-09 12:33:30 -04:00
Jagandeep Brar
d91cb05f66 chore(ci): skip Dart analyzer for builds
[skip ci]
2022-06-24 15:51:03 -04:00
Jagandeep Brar
d48d3d3ede chore(ci): use "latest" tag on stable Docker web releases
[skip ci]
2022-06-24 15:46:41 -04:00
Jagandeep Brar
18ef4cf1d4 fix(locale): create stub primary language localization assets 2022-06-24 12:55:04 -04:00
Jagandeep Brar
e05b17ae5e fix: display 0-length timestamps as "0 Minutes" instead of "Under a Minute" 2022-06-24 11:22:14 -04:00
Jagandeep Brar
16aa0a0dd1 chore: upgrade to Flutter 3.0.3/ffe7b86a1e
[skip ci]
2022-06-24 11:20:53 -04:00
Jagandeep Brar
925f163e15 feat(calendar): show current month in header 2022-06-24 09:21:41 -04:00
Jagandeep Brar
7ad952fbde chore(ci): remove ability to trigger specific-platform builds
[skip ci]
2022-06-22 17:29:30 -04:00
Jagandeep Brar
c71222aa7f chore(ci): fix Discord notification
[skip ci]
2022-06-22 17:05:11 -04:00
Jagandeep Brar
9f0615609d chore: update Firebase packages 2022-06-22 00:40:19 -04:00
Jagandeep Brar
141ae8f3f6 chore(ci): publish edge changelogs and update Discord embed layout 2022-06-21 23:50:25 -04:00
Jagandeep Brar
2e90ba36a9 chore: use Git commit message as changelog for edge releases 2022-06-20 22:32:08 -04:00
Jagandeep Brar
ff08010eca chore: add @Brokeos, @punchy98 to CONTRIBUTORS.md
[skip ci]
2022-06-20 22:31:20 -04:00
Weblate (bot)
904a07a2c6 chore: translations update from Hosted Weblate (#684)
[skip ci]

Co-authored-by: Brokeos <brokeos@outlook.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: 愿你多年归来仍是少年 <onestime@126.com>
Co-authored-by: punchy <michael@maldonado.tech>
2022-06-20 22:29:22 -04:00
Jagandeep Brar
2f3e2e0819 chore: use Git commit message as changelog for edge releases 2022-06-20 14:14:24 -04:00
Jagandeep Brar
80678a75bb fix(sonarr): invalid linking to theTVDB content
[skip ci]
2022-06-20 13:12:19 -04:00
Jagandeep Brar
fb3e8e5325 fix(database): fallback to defaults on null values in profile 2022-06-18 12:58:58 -04:00
Jagandeep Brar
d4d9816c94 fix(database): utilize stricter typing for module headers map
[skip ci]
2022-06-17 02:43:46 -04:00
Jagandeep Brar
433978e1db chore(ci): utilize snapcore/action-publish@master 2022-06-17 02:34:45 -04:00
Jagandeep Brar
9c6016edc9 chore: support localization in most DateTime conversions 2022-06-17 01:20:25 -04:00
Jagandeep Brar
8b5745044e feat(locale): support Vietnamese (vi)
[skip ci]
2022-06-15 17:19:05 -04:00
Jagandeep Brar
d16ab20a50 chore: remove generated file
[skip ci]
2022-06-15 01:39:04 -04:00
Jagandeep Brar
aff6e2ca18 fix(ci): utilize latest standard for Snapcraft login
[skip ci]
2022-06-15 01:35:59 -04:00
Jagandeep Brar
d8506ee283 fix(database): validate enabled profile exists on restore 2022-06-15 00:33:14 -04:00
Jagandeep Brar
910bb432f2 chore(shaders): upgrade to Flutter 3.0.2/f15f824b57
[skip ci]
2022-06-15 00:33:14 -04:00
Jagandeep Brar
95a645c06c fix(lists): reorderable lists could not be reordered on some platforms 2022-06-15 00:33:14 -04:00
Jagandeep Brar
6ad93549b1 chore(env): remove .env
[skip ci]
2022-06-15 00:33:14 -04:00
Jagandeep Brar
a643c09667 chore(gen): remove Envify build target
[skip ci]
2022-06-14 18:06:09 -04:00
Jagandeep Brar
9fd5bb6beb chore(contributors): add @iHunterX to CONTRIBUTORS.md
[skip ci]
2022-06-14 18:04:45 -04:00
Weblate (bot)
e0fd501ba5 chore: translations update from Hosted Weblate (#679) [skip ci]
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: 愿你多年归来仍是少年 <onestime@126.com>
Co-authored-by: Maxime Leroy <lisacintosh@gmail.com>
Co-authored-by: Dinh Xuan Loc <loc.dx2903@gmail.com>
Co-authored-by: Jagandeep Brar <me@jagandeepbrar.io>
2022-06-14 18:02:40 -04:00
Jagandeep Brar
c4dd509e32 refactor(environment): load environment using environment_config 2022-06-14 17:52:17 -04:00
Jagandeep Brar
ef9bbaf265 chore(release): v10.1.0
[skip ci]
2022-06-14 17:52:17 -04:00
Jagandeep Brar
5d52440a43 refactor(core): destructure core folder and reintegrate extensions 2022-06-14 17:52:17 -04:00
Jagandeep Brar
19475ac193 chore: separate keys and data in LunaBox accessors 2022-06-14 17:52:17 -04:00
Jagandeep Brar
16b1b991a4 chore: rewrite profile system interface 2022-06-14 17:52:17 -04:00
Jagandeep Brar
446e2308d9 chore(database): further clean-up and refactoring 2022-06-14 17:52:17 -04:00
Jagandeep Brar
9cb3fabdf1 refactor: refactored in-app purchase interface 2022-06-14 17:52:17 -04:00
Jagandeep Brar
11015f3e36 chore(core): removed additional canonical export files
[skip ci]
2022-05-31 23:58:48 -04:00
Jagandeep Brar
9f3c3f779d refactor: utilize statics and class functions for LunaModule enum
[skip ci]
2022-05-31 23:49:48 -04:00
Jagandeep Brar
8fe81d11ab fix(database): correctly store manually ordered module list 2022-05-31 23:02:04 -04:00
Jagandeep Brar
a0eaca084a refactor(database): rewrite interface to key-value database 2022-05-31 21:12:38 -04:00
Jagandeep Brar
f136f532dd chore: bump to v10.0.4
[skip ci]
2022-05-26 22:49:55 -04:00
Jagandeep Brar
89241c7093 chore(release): stable release
[skip ci]
2022-05-26 12:31:55 -04:00
Jagandeep Brar
7c93dbb3f4 chore(release): candidate release
[skip ci]
2022-05-26 08:51:37 -04:00
Jagandeep Brar
4744f4d997 chore(release): beta release
[skip ci]
2022-05-26 01:20:13 -04:00
640 changed files with 8098 additions and 9777 deletions

View File

@@ -268,6 +268,60 @@
"contributions": [
"translation"
]
},
{
"login": "iHunterX",
"name": "iHunterX",
"avatar_url": "https://avatars.githubusercontent.com/u/16854718?v=4",
"profile": "https://github.com/iHunterX",
"contributions": [
"translation"
]
},
{
"login": "Brokeos",
"name": "Brokeos",
"avatar_url": "https://avatars.githubusercontent.com/u/8388746?v=4",
"profile": "https://github.com/Brokeos",
"contributions": [
"translation"
]
},
{
"login": "punchy98",
"name": "Michael Maldonado",
"avatar_url": "https://avatars.githubusercontent.com/u/12002902?v=4",
"profile": "https://github.com/punchy98",
"contributions": [
"translation"
]
},
{
"login": "natiz",
"name": "natiz",
"avatar_url": "https://avatars.githubusercontent.com/u/3515888?v=4",
"profile": "https://github.com/natiz",
"contributions": [
"code"
]
},
{
"login": "KevoM",
"name": "KevoM",
"avatar_url": "https://avatars.githubusercontent.com/u/8274366?v=4",
"profile": "https://github.com/KevoM",
"contributions": [
"translation"
]
},
{
"login": "rogeriomendes",
"name": "rogeriomendes",
"avatar_url": "https://avatars.githubusercontent.com/u/1494503?v=4",
"profile": "https://github.com/rogeriomendes",
"contributions": [
"translation"
]
}
],
"contributorsPerLine": 8,

View File

@@ -11,7 +11,8 @@
"docs",
"feat",
"fix",
"refactor"
"refactor",
"release"
]
]
}

4
.czrc
View File

@@ -9,6 +9,10 @@
"description": "Documentation only changes",
"title": "Documentation"
},
"release": {
"description": "A commit intended for publishing a new release",
"title": "Release"
},
"feat": {
"description": "A code change that implements a new feature",
"title": "Feature"

3
.env
View File

@@ -1,3 +0,0 @@
FLAVOR=edge
COMMIT=master
BUILD=9999999999

View File

@@ -23,10 +23,6 @@ inputs:
description: 'Google Play Store API Key'
required: false
default: ''
snapcraft-token:
description: 'Snapcraft API Key'
required: false
default: ''
runs:
using: composite
@@ -48,12 +44,6 @@ runs:
with:
bundler-cache: true
- name: Install Snapcraft
if: ${{ inputs.channel == 'snapcraft' }}
uses: samuelmeuli/action-snapcraft@v1
with:
snapcraft_token: ${{ inputs.snapcraft-token }}
- name: Install XCode
if: ${{ inputs.channel == 'app-store' }}
uses: maxim-lobanov/setup-xcode@v1

36
.github/scripts/notify-embed.js vendored Normal file
View File

@@ -0,0 +1,36 @@
const getRelease = () => {
const title = process.env.BUILD_TITLE;
let url = "https://builds.lunasea.app";
if (title) url += `/#${title}/`;
return `[Download](${url})`;
};
const getWeb = () => {
const flavor = process.env.BUILD_FLAVOR;
let url = "";
if (flavor !== "stable") url += `${process.env.BUILD_FLAVOR}.`;
url += "web.lunasea.app";
return `[View Deployment](https://${url})`;
};
module.exports = () => {
return JSON.stringify([
{
title: process.env.BUILD_TITLE ?? "Unknown Build",
color: 5164195,
timestamp: new Date().toISOString(),
fields: [
{
name: "Release",
value: getRelease(),
inline: true,
},
{
name: "Web",
value: getWeb(),
inline: true,
},
],
},
]);
};

View File

@@ -3,10 +3,10 @@ name: 'Build Web'
on:
workflow_call:
inputs:
build-title:
build-flavor:
required: true
type: string
flavor:
build-title:
required: true
type: string
@@ -68,14 +68,27 @@ jobs:
with:
platform: web
- name: Determine Tags
id: tags
uses: actions/github-script@v6
env:
BUILD_FLAVOR: ${{ inputs.build-flavor }}
BUILD_TITLE: ${{ inputs.build-title }}
with:
result-encoding: string
script: |
const tags = [];
tags.push(process.env.BUILD_FLAVOR);
tags.push(process.env.BUILD_TITLE);
if (process.env.BUILD_FLAVOR === 'stable') tags.push('latest');
return tags.map((tag) => `ghcr.io/jagandeepbrar/lunasea:${tag}`).join(',');
- name: Build LunaSea
uses: docker/build-push-action@v2
with:
context: .
outputs: type=docker,dest=${{ github.workspace}}/output/lunasea-web-docker.tar
tags: |
ghcr.io/jagandeepbrar/lunasea:${{ inputs.build-title }}
ghcr.io/jagandeepbrar/lunasea:${{ inputs.flavor }}
tags: ${{ steps.tags.outputs.result }}
- name: Upload Artifact
uses: actions/upload-artifact@v3

View File

@@ -3,30 +3,15 @@ name: Notify
on:
workflow_call:
inputs:
build-changelog:
required: true
type: string
build-flavor:
required: true
type: string
build-title:
required: true
type: string
flavor:
required: true
type: string
enable-android:
required: true
type: string
enable-ios:
required: true
type: string
enable-linux:
required: true
type: string
enable-macos:
required: true
type: string
enable-web:
required: true
type: string
enable-windows:
required: true
type: string
secrets:
DISCORD_WEBHOOK_EDGE:
@@ -43,6 +28,11 @@ jobs:
name: Discord
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Determine Webhook Channel
id: webhook
uses: actions/github-script@v6
@@ -51,12 +41,11 @@ jobs:
DISCORD_WEBHOOK_BETA: ${{ secrets.DISCORD_WEBHOOK_BETA }}
DISCORD_WEBHOOK_CANDIDATE: ${{ secrets.DISCORD_WEBHOOK_CANDIDATE }}
DISCORD_WEBHOOK_STABLE: ${{ secrets.DISCORD_WEBHOOK_STABLE }}
FLAVOR: ${{ inputs.flavor }}
BUILD_FLAVOR: ${{ inputs.build-flavor }}
with:
result-encoding: string
script: |
const ref = process.env.FLAVOR || 'edge';
switch (ref) {
switch (process.env.BUILD_FLAVOR) {
case 'beta': return process.env.DISCORD_WEBHOOK_BETA;
case 'candidate': return process.env.DISCORD_WEBHOOK_CANDIDATE;
case 'stable': return process.env.DISCORD_WEBHOOK_STABLE;
@@ -64,45 +53,21 @@ jobs:
default: return process.env.DISCORD_WEBHOOK_EDGE;
}
- name: Create Discord Message
id: message
- name: Create Discord Embed
id: embed
uses: actions/github-script@v6
env:
BUILD_CHANGELOG: ${{ inputs.build-changelog }}
BUILD_FLAVOR: ${{ inputs.build-flavor }}
BUILD_TITLE: ${{ inputs.build-title }}
ANDROID: ${{ inputs.enable-android }}
IOS: ${{ inputs.enable-ios }}
LINUX: ${{ inputs.enable-linux }}
MACOS: ${{ inputs.enable-macos }}
WEB: ${{ inputs.enable-web }}
WINDOWS: ${{ inputs.enable-windows }}
with:
result-encoding: string
script: |
const { ANDROID, IOS, LINUX, MACOS, WEB, WINDOWS } = process.env;
const url = `https://builds.lunasea.app/#${ process.env.BUILD_TITLE }/`;
let _base = `[Download](${url})`;
if ( ANDROID || IOS || LINUX || MACOS || WEB || WINDOWS) {
_base += '\n\nThis release is available on the following platforms: ';
const platforms = [];
if (ANDROID === 'true') platforms.push('Android');
if (IOS === 'true') platforms.push('iOS');
if (LINUX === 'true') platforms.push('Linux');
if (MACOS === 'true') platforms.push('macOS');
if (WEB === 'true') platforms.push('Web');
if (WINDOWS === 'true') platforms.push('Windows');
_base += platforms.map((p) => `**${p}**`).join(', ');
}
return _base;
script: return require('.github/scripts/notify-embed.js')();
- name: Send Discord Message
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ steps.webhook.outputs.result }}
username: LunaSea Support
avatar_url: https://raw.githubusercontent.com/JagandeepBrar/LunaSea/master/assets/icon/icon.png
noprefix: true
color: 0x4ECCA3
title: ${{ inputs.build-title }}
description: ${{ steps.message.outputs.result }}
uses: Ilshidur/action-discord@0.3.2
env:
DISCORD_WEBHOOK: ${{ steps.webhook.outputs.result }}
DISCORD_USERNAME: LunaSea Support
DISCORD_AVATAR: https://raw.githubusercontent.com/JagandeepBrar/LunaSea/master/assets/icon/icon.png
DISCORD_EMBEDS: ${{ steps.embed.outputs.result }}

View File

@@ -8,6 +8,12 @@ on:
required: true
outputs:
build-changelog:
description: "Build Changelog"
value: ${{ jobs.build-details.outputs.build-changelog }}
build-flavor:
description: "Build Flavor"
value: ${{ jobs.build-details.outputs.build-flavor }}
build-number:
description: "Build Number"
value: ${{ jobs.build-details.outputs.build-number }}
@@ -17,143 +23,18 @@ on:
build-version:
description: "Build Version"
value: ${{ jobs.build-details.outputs.build-version }}
enable-android:
description: "Is Android Enabled?"
value: ${{ jobs.platform-list.outputs.android }}
enable-ios:
description: "Is iOS Enabled?"
value: ${{ jobs.platform-list.outputs.ios }}
enable-linux:
description: "Is Linux Enabled?"
value: ${{ jobs.platform-list.outputs.linux }}
enable-macos:
description: "Is macOS Enabled?"
value: ${{ jobs.platform-list.outputs.macos }}
enable-windows:
description: "Is Windows Enabled?"
value: ${{ jobs.platform-list.outputs.windows }}
enable-web:
description: "Is Web Enabled?"
value: ${{ jobs.platform-list.outputs.web }}
secrets:
FIREBASE_TOKEN:
required: true
jobs:
platform-list:
name: Platform List
runs-on: ubuntu-latest
outputs:
android: ${{ steps.android.outputs.result }}
ios: ${{ steps.ios.outputs.result }}
linux: ${{ steps.linux.outputs.result }}
macos: ${{ steps.macos.outputs.result }}
windows: ${{ steps.windows.outputs.result }}
web: ${{ steps.web.outputs.result }}
steps:
- name: Check Message for Any Keywords
id: exists
uses: actions/github-script@v6
env:
MESSAGE: ${{ github.event.head_commit.message || '' }}
with:
result-encoding: string
script: |
return process.env.MESSAGE.includes("platform:");
- name: Android
id: android
uses: actions/github-script@v6
env:
EXISTS: ${{ steps.exists.outputs.result }}
MESSAGE: ${{ github.event.head_commit.message || '' }}
with:
result-encoding: string
script: |
if (process.env.EXISTS === "false") return true;
return process.env.MESSAGE.includes("platform:android");
- name: iOS
id: ios
uses: actions/github-script@v6
env:
EXISTS: ${{ steps.exists.outputs.result }}
MESSAGE: ${{ github.event.head_commit.message || '' }}
with:
result-encoding: string
script: |
if (process.env.EXISTS === "false") return true;
return process.env.MESSAGE.includes("platform:ios");
- name: Linux
id: linux
uses: actions/github-script@v6
env:
EXISTS: ${{ steps.exists.outputs.result }}
MESSAGE: ${{ github.event.head_commit.message || '' }}
with:
result-encoding: string
script: |
if (process.env.EXISTS === "false") return true;
return process.env.MESSAGE.includes("platform:linux");
- name: macOS
id: macos
uses: actions/github-script@v6
env:
EXISTS: ${{ steps.exists.outputs.result }}
MESSAGE: ${{ github.event.head_commit.message || '' }}
with:
result-encoding: string
script: |
if (process.env.EXISTS === "false") return true;
return process.env.MESSAGE.includes("platform:macos");
- name: Web
id: web
uses: actions/github-script@v6
env:
EXISTS: ${{ steps.exists.outputs.result }}
MESSAGE: ${{ github.event.head_commit.message || '' }}
with:
result-encoding: string
script: |
if (process.env.EXISTS === "false") return true;
return process.env.MESSAGE.includes("platform:web");
- name: Windows
id: windows
uses: actions/github-script@v6
env:
EXISTS: ${{ steps.exists.outputs.result }}
MESSAGE: ${{ github.event.head_commit.message || '' }}
with:
result-encoding: string
script: |
if (process.env.EXISTS === "false") return true;
return process.env.MESSAGE.includes("platform:windows");
- name: Log Platform List
env:
android: ${{ steps.android.outputs.result }}
ios: ${{ steps.ios.outputs.result }}
linux: ${{ steps.linux.outputs.result }}
macos: ${{ steps.macos.outputs.result }}
windows: ${{ steps.windows.outputs.result }}
web: ${{ steps.web.outputs.result }}
run: |
echo "Android: $android"
echo "iOS: $ios"
echo "Linux: $linux"
echo "macOS: $macos"
echo "Web: $web"
echo "Windows: $windows"
build-details:
name: Build Details
runs-on: ubuntu-latest
outputs:
build-changelog: ${{ steps.build-changelog.outputs.result }}
build-flavor: ${{ steps.build-flavor.outputs.result }}
build-number: ${{ steps.build-number.outputs.result }}
build-title: ${{ steps.build-title.outputs.output }}
build-version: ${{ steps.build-version.outputs.current-version }}
@@ -162,18 +43,45 @@ jobs:
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Count Commits
id: commit_count
id: commit-count
run: |
COUNT=`git rev-list HEAD --count`
echo "::set-output name=commit_count::$COUNT"
echo "::set-output name=commit-count::$COUNT"
- name: Build Flavor
id: build-flavor
uses: actions/github-script@v6
env:
FLAVOR: ${{ inputs.flavor }}
with:
result-encoding: string
script: |
const flavor = process.env.FLAVOR;
if (flavor) switch (flavor) {
case 'edge':
case 'beta':
case 'candidate':
case 'stable':
return flavor;
}
return 'edge';
- name: Build Changelog
id: build-changelog
uses: actions/github-script@v6
env:
FLAVOR: ${{ steps.build-flavor.outputs.result }}
with:
result-encoding: string
script: return `Thank you for testing ${process.env.FLAVOR} release builds! All changes can be found within the application.`;
- name: Build Number
id: build-number
uses: actions/github-script@v6
env:
COUNT: ${{ steps.commit_count.outputs.commit_count }}
COUNT: ${{ steps.commit-count.outputs.commit-count }}
with:
result-encoding: string
script: |
@@ -189,18 +97,22 @@ jobs:
id: build-title
run: |
HASH=`git rev-parse --short ${{ github.sha }}`
TITLE="v${{ steps.build-version.outputs.current-version }}-${{ inputs.flavor }}-${{ steps.build-number.outputs.result }}-$HASH"
TITLE="v${{ steps.build-version.outputs.current-version }}-${{ steps.build-flavor.outputs.result }}-${{ steps.build-number.outputs.result }}-$HASH"
echo "::set-output name=output::$TITLE"
- name: Log Build Details
env:
number: ${{ steps.build-number.outputs.result }}
title: ${{ steps.build-title.outputs.output }}
version: ${{ steps.build-version.outputs.current-version }}
CHANGELOG: ${{ steps.build-changelog.outputs.result }}
FLAVOR: ${{ steps.build-flavor.outputs.result }}
NUMBER: ${{ steps.build-number.outputs.result }}
TITLE: ${{ steps.build-title.outputs.output }}
VERSION: ${{ steps.build-version.outputs.current-version }}
run: |
echo "Build Number: $number"
echo "Build Title: $title"
echo "Build Version: $version"
echo "Build Changelog: $CHANGELOG"
echo "Build Flavor: $FLAVOR"
echo "Build Number: $NUMBER"
echo "Build Title: $TITLE"
echo "Build Version: $VERSION"
generate-files:
name: Generate Files
@@ -216,21 +128,26 @@ jobs:
- name: Generate Environment Configuration
run: |
echo FLAVOR=${{ inputs.flavor }} > .env
echo COMMIT=${{ github.sha }} >> .env
echo BUILD=${{ needs.build-details.outputs.build-number }} >> .env
export FLAVOR=${{ needs.build-details.outputs.build-flavor }}
export COMMIT=${{ github.sha }}
export BUILD=${{ needs.build-details.outputs.build-number }}
flutter packages pub run environment_config:generate
- name: Generate Localization
run: dart ${{github.workspace }}/scripts/generate_localization.dart
- name: Generate Changelog
run: dart ${{github.workspace }}/scripts/generate_changelog.dart ${{ needs.build-details.outputs.build-flavor }}
- name: Generate Build Runner Files
run: flutter packages pub run build_runner build
- name: Upload Core Files
uses: actions/upload-artifact@v3
with:
name: core-files
path: |
${{ github.workspace }}/.env
${{ github.workspace }}/assets/changelog.json
${{ github.workspace }}/assets/localization
${{ github.workspace }}/lib/**/*.g.dart
${{ github.workspace }}/lib/system/environment.dart

View File

@@ -3,29 +3,19 @@ name: Publish Android
on:
workflow_call:
inputs:
build-number:
build-changelog:
required: true
type: string
build-flavor:
required: true
type: string
build-title:
required: true
type: string
flavor:
required: true
type: string
secrets:
GOOGLE_PLAY_API:
required: true
S3_ACCESS_KEY:
required: true
S3_BUCKET:
required: true
S3_ENDPOINT:
required: true
S3_KEY_ID:
required: true
S3_REGION:
required: true
jobs:
play-store:
@@ -48,7 +38,7 @@ jobs:
id: channel
uses: actions/github-script@v6
env:
FLAVOR: ${{ inputs.flavor }}
FLAVOR: ${{ inputs.build-flavor }}
with:
result-encoding: string
script: |
@@ -60,54 +50,17 @@ jobs:
case 'edge':
default: return 'internal';
}
- name: Generate Changelog
env:
CHANGELOG: ${{ inputs.build-changelog }}
CHANGELOG_PATH: ${{ github.workspace }}/android/fastlane/metadata/android/en-CA/changelogs
run: |
mkdir -p $CHANGELOG_PATH
echo $CHANGELOG > $CHANGELOG_PATH/default.txt
- name: Deploy to Google Play Store
working-directory: ${{ github.workspace }}/android
env:
SUPPLY_JSON_KEY: ${{ github.workspace }}/keys/googleplay.json
run: bundle exec fastlane deploy_playstore track:${{ steps.channel.outputs.result }} aab:${{ github.workspace }}/output/lunasea-android.aab version_name:${{ inputs.build-title }}
s3:
name: S3
runs-on: ubuntu-latest
steps:
- name: Setup Environment
uses: JagandeepBrar/LunaSea/.github/actions/prepare_for_deployment@master
with:
channel: s3
- name: Download Android App Package
uses: actions/download-artifact@v3
with:
name: android-app-package
path: ${{ github.workspace }}/output
- name: Upload to S3 Bucket (Build Title)
uses: jakejarvis/s3-sync-action@v0.5.1
with:
args: --acl public-read --follow-symlinks
env:
AWS_ACCESS_KEY_ID: ${{ secrets.S3_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET }}
AWS_S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
AWS_REGION: ${{ secrets.S3_REGION }}
SOURCE_DIR: ${{ github.workspace }}/output
DEST_DIR: ${{ inputs.build-title }}
- name: Create Version File
working-directory: ${{ github.workspace }}/output
run: echo ${{ inputs.build-number }} > VERSION_ANDROID.txt
- name: Upload to S3 Bucket (Latest)
uses: jakejarvis/s3-sync-action@v0.5.1
with:
args: --acl public-read --follow-symlinks
env:
AWS_ACCESS_KEY_ID: ${{ secrets.S3_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET }}
AWS_S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
AWS_REGION: ${{ secrets.S3_REGION }}
SOURCE_DIR: ${{ github.workspace }}/output
DEST_DIR: latest/${{ inputs.flavor }}

View File

@@ -3,13 +3,10 @@ name: Publish iOS
on:
workflow_call:
inputs:
build-number:
build-changelog:
required: true
type: string
build-title:
required: true
type: string
flavor:
build-flavor:
required: true
type: string
@@ -26,16 +23,6 @@ on:
required: true
APPLE_TEAM_ID:
required: true
S3_ACCESS_KEY:
required: true
S3_BUCKET:
required: true
S3_ENDPOINT:
required: true
S3_KEY_ID:
required: true
S3_REGION:
required: true
jobs:
app-store:
@@ -53,7 +40,15 @@ jobs:
with:
name: ios-appstore-package
path: ${{ github.workspace }}/output
- name: Generate Changelog
env:
CHANGELOG: ${{ inputs.build-changelog }}
CHANGELOG_PATH: ${{ github.workspace }}/ios/fastlane
run: |
mkdir -p $CHANGELOG_PATH
echo $CHANGELOG > $CHANGELOG_PATH/changelog.txt
- name: Deploy to App Store Connect
working-directory: ${{ github.workspace }}/ios
env:
@@ -63,49 +58,4 @@ jobs:
APPLE_STORE_CONNECT_KEY_FILEPATH: ${{ github.workspace }}/keys/appstore.p8
APPLE_STORE_CONNECT_KEY_ID: ${{ secrets.APPLE_STORE_CONNECT_KEY_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: bundle exec fastlane deploy_appstore groups:${{ inputs.flavor }} ipa:${{ github.workspace }}/output/lunasea-ios.ipa
s3:
name: S3
runs-on: ubuntu-latest
steps:
- name: Setup Environment
uses: JagandeepBrar/LunaSea/.github/actions/prepare_for_deployment@master
with:
channel: s3
- name: Download iOS App Package
uses: actions/download-artifact@v3
with:
name: ios-appstore-package
path: ${{ github.workspace }}/output
- name: Upload to S3 Bucket (Build Title)
uses: jakejarvis/s3-sync-action@v0.5.1
with:
args: --acl public-read --follow-symlinks
env:
AWS_ACCESS_KEY_ID: ${{ secrets.S3_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET }}
AWS_S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
AWS_REGION: ${{ secrets.S3_REGION }}
SOURCE_DIR: ${{ github.workspace }}/output
DEST_DIR: ${{ inputs.build-title }}
- name: Create Version File
working-directory: ${{ github.workspace }}/output
run: echo ${{ inputs.build-number }} > VERSION_IOS.txt
- name: Upload to S3 Bucket (Latest)
uses: jakejarvis/s3-sync-action@v0.5.1
with:
args: --acl public-read --follow-symlinks
env:
AWS_ACCESS_KEY_ID: ${{ secrets.S3_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET }}
AWS_S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
AWS_REGION: ${{ secrets.S3_REGION }}
SOURCE_DIR: ${{ github.workspace }}/output
DEST_DIR: latest/${{ inputs.flavor }}
run: bundle exec fastlane deploy_appstore groups:${{ inputs.build-flavor }} ipa:${{ github.workspace }}/output/lunasea-ios.ipa

View File

@@ -3,28 +3,12 @@ name: Publish Linux
on:
workflow_call:
inputs:
build-number:
required: true
type: string
build-title:
required: true
type: string
flavor:
build-flavor:
required: true
type: string
secrets:
SNAPCRAFT_TOKEN:
required: true
S3_ACCESS_KEY:
required: true
S3_BUCKET:
required: true
S3_ENDPOINT:
required: true
S3_KEY_ID:
required: true
S3_REGION:
SNAPCRAFT_STORE_CREDENTIALS:
required: true
jobs:
@@ -36,7 +20,6 @@ jobs:
uses: JagandeepBrar/LunaSea/.github/actions/prepare_for_deployment@master
with:
channel: snapcraft
snapcraft-token: ${{ secrets.SNAPCRAFT_TOKEN }}
- name: Download Snap
uses: actions/download-artifact@v3
@@ -45,49 +28,9 @@ jobs:
path: ${{ github.workspace }}/output
- name: Deploy to Snapcraft
run: snapcraft upload --release=${{ inputs.flavor }} ${{ github.workspace }}/output/lunasea-linux-amd64.snap
s3:
name: S3
runs-on: ubuntu-latest
steps:
- name: Setup Environment
uses: JagandeepBrar/LunaSea/.github/actions/prepare_for_deployment@master
with:
channel: s3
- name: Download Linux Snap
uses: actions/download-artifact@v3
with:
name: linux-snapcraft
path: ${{ github.workspace }}/output
- name: Upload to S3 Bucket (Build Title)
uses: jakejarvis/s3-sync-action@v0.5.1
with:
args: --acl public-read --follow-symlinks
uses: snapcore/action-publish@master
env:
AWS_ACCESS_KEY_ID: ${{ secrets.S3_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET }}
AWS_S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
AWS_REGION: ${{ secrets.S3_REGION }}
SOURCE_DIR: ${{ github.workspace }}/output
DEST_DIR: ${{ inputs.build-title }}
- name: Create Version File
working-directory: ${{ github.workspace }}/output
run: echo ${{ inputs.build-number }} > VERSION_LINUX.txt
- name: Upload to S3 Bucket (Latest)
uses: jakejarvis/s3-sync-action@v0.5.1
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
with:
args: --acl public-read --follow-symlinks
env:
AWS_ACCESS_KEY_ID: ${{ secrets.S3_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET }}
AWS_S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
AWS_REGION: ${{ secrets.S3_REGION }}
SOURCE_DIR: ${{ github.workspace }}/output
DEST_DIR: latest/${{ inputs.flavor }}
release: ${{ inputs.build-flavor }}
snap: ${{ github.workspace }}/output/lunasea-linux-amd64.snap

View File

@@ -3,13 +3,10 @@ name: Publish macOS
on:
workflow_call:
inputs:
build-number:
build-changelog:
required: true
type: string
build-title:
required: true
type: string
flavor:
build-flavor:
required: true
type: string
@@ -26,16 +23,6 @@ on:
required: true
APPLE_TEAM_ID:
required: true
S3_ACCESS_KEY:
required: true
S3_BUCKET:
required: true
S3_ENDPOINT:
required: true
S3_KEY_ID:
required: true
S3_REGION:
required: true
jobs:
app-store:
@@ -53,7 +40,15 @@ jobs:
with:
name: macos-appstore-package
path: ${{ github.workspace }}/output
- name: Generate Changelog
env:
CHANGELOG: ${{ inputs.build-changelog }}
CHANGELOG_PATH: ${{ github.workspace }}/macos/fastlane
run: |
mkdir -p $CHANGELOG_PATH
echo $CHANGELOG > $CHANGELOG_PATH/changelog.txt
- name: Deploy to App Store Connect
working-directory: ${{ github.workspace }}/macos
env:
@@ -63,55 +58,4 @@ jobs:
APPLE_STORE_CONNECT_KEY_FILEPATH: ${{ github.workspace }}/keys/appstore.p8
APPLE_STORE_CONNECT_KEY_ID: ${{ secrets.APPLE_STORE_CONNECT_KEY_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: bundle exec fastlane deploy_appstore groups:${{ inputs.flavor }} pkg:${{ github.workspace }}/output/lunasea-macos-amd64.pkg
s3:
name: S3
runs-on: ubuntu-latest
steps:
- name: Setup Environment
uses: JagandeepBrar/LunaSea/.github/actions/prepare_for_deployment@master
with:
channel: s3
- name: Download macOS App Package
uses: actions/download-artifact@v3
with:
name: macos-app-package
path: ${{ github.workspace }}/output
- name: Download macOS Disk Image
uses: actions/download-artifact@v3
with:
name: macos-disk-image
path: ${{ github.workspace }}/output
- name: Upload to S3 Bucket (Build Title)
uses: jakejarvis/s3-sync-action@v0.5.1
with:
args: --acl public-read --follow-symlinks
env:
AWS_ACCESS_KEY_ID: ${{ secrets.S3_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET }}
AWS_S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
AWS_REGION: ${{ secrets.S3_REGION }}
SOURCE_DIR: ${{ github.workspace }}/output
DEST_DIR: ${{ inputs.build-title }}
- name: Create Version File
working-directory: ${{ github.workspace }}/output
run: echo ${{ inputs.build-number }} > VERSION_MACOS.txt
- name: Upload to S3 Bucket (Latest)
uses: jakejarvis/s3-sync-action@v0.5.1
with:
args: --acl public-read --follow-symlinks
env:
AWS_ACCESS_KEY_ID: ${{ secrets.S3_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET }}
AWS_S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
AWS_REGION: ${{ secrets.S3_REGION }}
SOURCE_DIR: ${{ github.workspace }}/output
DEST_DIR: latest/${{ inputs.flavor }}
run: bundle exec fastlane deploy_appstore groups:${{ inputs.build-flavor }} pkg:${{ github.workspace }}/output/lunasea-macos-amd64.pkg

View File

@@ -1,17 +1,17 @@
name: Publish Windows
name: Publish s3
on:
workflow_call:
inputs:
build-flavor:
required: true
type: string
build-number:
required: true
type: string
build-title:
required: true
type: string
flavor:
required: true
type: string
secrets:
S3_ACCESS_KEY:
@@ -35,6 +35,42 @@ jobs:
with:
channel: s3
- name: Download Android App Package
uses: actions/download-artifact@v3
with:
name: android-app-package
path: ${{ github.workspace }}/output
- name: Download iOS App Package
uses: actions/download-artifact@v3
with:
name: ios-appstore-package
path: ${{ github.workspace }}/output
- name: Download Linux Snap
uses: actions/download-artifact@v3
with:
name: linux-snapcraft
path: ${{ github.workspace }}/output
- name: Download macOS App Package
uses: actions/download-artifact@v3
with:
name: macos-app-package
path: ${{ github.workspace }}/output
- name: Download macOS Disk Image
uses: actions/download-artifact@v3
with:
name: macos-disk-image
path: ${{ github.workspace }}/output
- name: Download Web Archive
uses: actions/download-artifact@v3
with:
name: web-archive
path: ${{ github.workspace }}/output
- name: Download Windows App Package
uses: actions/download-artifact@v3
with:
@@ -47,6 +83,17 @@ jobs:
name: windows-msix-installer
path: ${{ github.workspace }}/output
- name: Create Version File
working-directory: ${{ github.workspace }}/output
run: |
echo ${{ inputs.build-number }} > VERSION.txt
echo ${{ inputs.build-number }} > VERSION_ANDROID.txt
echo ${{ inputs.build-number }} > VERSION_IOS.txt
echo ${{ inputs.build-number }} > VERSION_LINUX.txt
echo ${{ inputs.build-number }} > VERSION_MACOS.txt
echo ${{ inputs.build-number }} > VERSION_WEB.txt
echo ${{ inputs.build-number }} > VERSION_WINDOWS.txt
- name: Upload to S3 Bucket (Build Title)
uses: jakejarvis/s3-sync-action@v0.5.1
with:
@@ -60,10 +107,6 @@ jobs:
SOURCE_DIR: ${{ github.workspace }}/output
DEST_DIR: ${{ inputs.build-title }}
- name: Create Version File
working-directory: ${{ github.workspace }}/output
run: echo ${{ inputs.build-number }} > VERSION_WINDOWS.txt
- name: Upload to S3 Bucket (Latest)
uses: jakejarvis/s3-sync-action@v0.5.1
with:
@@ -75,4 +118,4 @@ jobs:
AWS_S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
AWS_REGION: ${{ secrets.S3_REGION }}
SOURCE_DIR: ${{ github.workspace }}/output
DEST_DIR: latest/${{ inputs.flavor }}
DEST_DIR: latest/${{ inputs.build-flavor }}

View File

@@ -3,29 +3,16 @@ name: Publish Web (Docker)
on:
workflow_call:
inputs:
build-number:
build-flavor:
required: true
type: string
build-title:
required: true
type: string
flavor:
required: true
type: string
secrets:
NETLIFY_AUTH_TOKEN:
required: true
S3_ACCESS_KEY:
required: true
S3_BUCKET:
required: true
S3_ENDPOINT:
required: true
S3_KEY_ID:
required: true
S3_REGION:
required: true
jobs:
docker:
@@ -46,9 +33,7 @@ jobs:
path: ${{ github.workspace }}/output
- name: Load Docker Image
run: |
docker load --input ${{ github.workspace}}/output/lunasea-web-docker.tar
docker image ls -a
run: docker load --input ${{ github.workspace}}/output/lunasea-web-docker.tar
- name: Deploy to GitHub Container Registry
run: docker image push --all-tags ghcr.io/jagandeepbrar/lunasea
@@ -72,7 +57,7 @@ jobs:
id: channel
uses: actions/github-script@v6
env:
FLAVOR: ${{ inputs.flavor }}
FLAVOR: ${{ inputs.build-flavor }}
with:
result-encoding: string
script: |
@@ -94,48 +79,3 @@ jobs:
publish-dir: ${{ github.workspace}}/output
production-deploy: true
deploy-message: ${{ inputs.build-title }}
s3:
name: S3
runs-on: ubuntu-latest
steps:
- name: Setup Environment
uses: JagandeepBrar/LunaSea/.github/actions/prepare_for_deployment@master
with:
channel: s3
- name: Download Web Archive
uses: actions/download-artifact@v3
with:
name: web-archive
path: ${{ github.workspace }}/output
- name: Upload to S3 Bucket (Build Title)
uses: jakejarvis/s3-sync-action@v0.5.1
with:
args: --acl public-read --follow-symlinks
env:
AWS_ACCESS_KEY_ID: ${{ secrets.S3_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET }}
AWS_S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
AWS_REGION: ${{ secrets.S3_REGION }}
SOURCE_DIR: ${{ github.workspace }}/output
DEST_DIR: ${{ inputs.build-title }}
- name: Create Version File
working-directory: ${{ github.workspace }}/output
run: echo ${{ inputs.build-number }} > VERSION_WEB.txt
- name: Upload to S3 Bucket (Latest)
uses: jakejarvis/s3-sync-action@v0.5.1
with:
args: --acl public-read --follow-symlinks
env:
AWS_ACCESS_KEY_ID: ${{ secrets.S3_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET }}
AWS_S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
AWS_REGION: ${{ secrets.S3_REGION }}
SOURCE_DIR: ${{ github.workspace }}/output
DEST_DIR: latest/${{ inputs.flavor }}

View File

@@ -22,21 +22,13 @@ jobs:
name: Prepare
uses: JagandeepBrar/LunaSea/.github/workflows/prepare.yml@master
with:
flavor: ${{ github.event.inputs.flavor || 'edge' }}
secrets:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
validate:
name: Validate
needs: [ prepare ]
uses: JagandeepBrar/LunaSea/.github/workflows/validate.yml@master
flavor: ${{ inputs.flavor }}
secrets:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
build-android:
name: Build Android
needs: [ prepare, validate ]
if: ${{ needs.prepare.outputs.enable-android == 'true' }}
needs: [ prepare ]
uses: JagandeepBrar/LunaSea/.github/workflows/build_android.yml@master
with:
build-number: ${{ needs.prepare.outputs.build-number }}
@@ -47,8 +39,7 @@ jobs:
build-ios:
name: Build iOS
needs: [ prepare, validate ]
if: ${{ needs.prepare.outputs.enable-ios == 'true' }}
needs: [ prepare ]
uses: JagandeepBrar/LunaSea/.github/workflows/build_ios.yml@master
with:
build-number: ${{ needs.prepare.outputs.build-number }}
@@ -65,14 +56,12 @@ jobs:
build-linux:
name: Build Linux
needs: [ prepare, validate ]
if: ${{ needs.prepare.outputs.enable-linux == 'true' }}
needs: [ prepare ]
uses: JagandeepBrar/LunaSea/.github/workflows/build_linux.yml@master
build-macos:
name: Build macOS
needs: [ prepare, validate ]
if: ${{ needs.prepare.outputs.enable-macos == 'true' }}
needs: [ prepare ]
uses: JagandeepBrar/LunaSea/.github/workflows/build_macos.yml@master
with:
build-number: ${{ needs.prepare.outputs.build-number }}
@@ -94,19 +83,17 @@ jobs:
build-web:
name: Build Web
needs: [ prepare, validate ]
if: ${{ needs.prepare.outputs.enable-web == 'true' }}
needs: [ prepare ]
uses: JagandeepBrar/LunaSea/.github/workflows/build_web.yml@master
with:
build-flavor: ${{ needs.prepare.outputs.build-flavor }}
build-title: ${{ needs.prepare.outputs.build-title }}
flavor: ${{ github.event.inputs.flavor || 'edge' }}
secrets:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
build-windows:
name: Build Windows
needs: [ prepare, validate ]
if: ${{ needs.prepare.outputs.enable-windows == 'true' }}
needs: [ prepare ]
uses: JagandeepBrar/LunaSea/.github/workflows/build_windows.yml@master
secrets:
CODE_SIGNING_CERTIFICATE: ${{ secrets.CODE_SIGNING_CERTIFICATE }}
@@ -119,25 +106,19 @@ jobs:
needs: [ prepare, build-android ]
uses: JagandeepBrar/LunaSea/.github/workflows/publish_android.yml@master
with:
flavor: ${{ github.event.inputs.flavor || 'edge' }}
build-number: ${{ needs.prepare.outputs.build-number }}
build-changelog: ${{ needs.prepare.outputs.build-changelog }}
build-flavor: ${{ needs.prepare.outputs.build-flavor }}
build-title: ${{ needs.prepare.outputs.build-title }}
secrets:
GOOGLE_PLAY_API: ${{ secrets.GOOGLE_PLAY_API }}
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
S3_BUCKET: ${{ secrets.S3_BUCKET }}
S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
S3_KEY_ID: ${{ secrets.S3_KEY_ID }}
S3_REGION: ${{ secrets.S3_REGION }}
publish-ios:
name: Publish iOS
needs: [ prepare, build-ios ]
uses: JagandeepBrar/LunaSea/.github/workflows/publish_ios.yml@master
with:
flavor: ${{ github.event.inputs.flavor || 'edge' }}
build-number: ${{ needs.prepare.outputs.build-number }}
build-title: ${{ needs.prepare.outputs.build-title }}
build-changelog: ${{ needs.prepare.outputs.build-changelog }}
build-flavor: ${{ needs.prepare.outputs.build-flavor }}
secrets:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ITC_TEAM_ID: ${{ secrets.APPLE_ITC_TEAM_ID }}
@@ -145,36 +126,23 @@ jobs:
APPLE_STORE_CONNECT_KEY: ${{ secrets.APPLE_STORE_CONNECT_KEY }}
APPLE_STORE_CONNECT_KEY_ID: ${{ secrets.APPLE_STORE_CONNECT_KEY_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
S3_BUCKET: ${{ secrets.S3_BUCKET }}
S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
S3_KEY_ID: ${{ secrets.S3_KEY_ID }}
S3_REGION: ${{ secrets.S3_REGION }}
publish-linux:
name: Publish Linux
needs: [ prepare, build-linux ]
uses: JagandeepBrar/LunaSea/.github/workflows/publish_linux.yml@master
with:
flavor: ${{ github.event.inputs.flavor || 'edge' }}
build-number: ${{ needs.prepare.outputs.build-number }}
build-title: ${{ needs.prepare.outputs.build-title }}
build-flavor: ${{ needs.prepare.outputs.build-flavor }}
secrets:
SNAPCRAFT_TOKEN: ${{ secrets.SNAPCRAFT_TOKEN }}
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
S3_BUCKET: ${{ secrets.S3_BUCKET }}
S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
S3_KEY_ID: ${{ secrets.S3_KEY_ID }}
S3_REGION: ${{ secrets.S3_REGION }}
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
publish-macos:
name: Publish macOS
needs: [ prepare, build-macos ]
uses: JagandeepBrar/LunaSea/.github/workflows/publish_macos.yml@master
with:
flavor: ${{ github.event.inputs.flavor || 'edge' }}
build-number: ${{ needs.prepare.outputs.build-number }}
build-title: ${{ needs.prepare.outputs.build-title }}
build-changelog: ${{ needs.prepare.outputs.build-changelog }}
build-flavor: ${{ needs.prepare.outputs.build-flavor }}
secrets:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ITC_TEAM_ID: ${{ secrets.APPLE_ITC_TEAM_ID }}
@@ -182,34 +150,23 @@ jobs:
APPLE_STORE_CONNECT_KEY: ${{ secrets.APPLE_STORE_CONNECT_KEY }}
APPLE_STORE_CONNECT_KEY_ID: ${{ secrets.APPLE_STORE_CONNECT_KEY_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
S3_BUCKET: ${{ secrets.S3_BUCKET }}
S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
S3_KEY_ID: ${{ secrets.S3_KEY_ID }}
S3_REGION: ${{ secrets.S3_REGION }}
publish-web:
name: Publish Web
needs: [ prepare, build-web ]
uses: JagandeepBrar/LunaSea/.github/workflows/publish_web.yml@master
with:
flavor: ${{ github.event.inputs.flavor || 'edge' }}
build-number: ${{ needs.prepare.outputs.build-number }}
build-flavor: ${{ needs.prepare.outputs.build-flavor }}
build-title: ${{ needs.prepare.outputs.build-title }}
secrets:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
S3_BUCKET: ${{ secrets.S3_BUCKET }}
S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
S3_KEY_ID: ${{ secrets.S3_KEY_ID }}
S3_REGION: ${{ secrets.S3_REGION }}
publish-windows:
name: Publish Windows
needs: [ prepare, build-windows ]
uses: JagandeepBrar/LunaSea/.github/workflows/publish_windows.yml@master
publish-s3:
name: Publish S3
needs: [ prepare, build-android, build-ios, build-linux, build-macos, build-web, build-windows ]
uses: JagandeepBrar/LunaSea/.github/workflows/publish_s3.yml@master
with:
flavor: ${{ github.event.inputs.flavor || 'edge' }}
build-flavor: ${{ needs.prepare.outputs.build-flavor }}
build-number: ${{ needs.prepare.outputs.build-number }}
build-title: ${{ needs.prepare.outputs.build-title }}
secrets:
@@ -221,26 +178,12 @@ jobs:
notify:
name: Notify
needs: [ prepare, publish-android, publish-ios, publish-linux, publish-macos, publish-web, publish-windows ]
if: |
always() &&
!cancelled() &&
(needs.publish-android.result == 'success' || needs.publish-android.result == 'skipped') &&
(needs.publish-ios.result == 'success' || needs.publish-ios.result == 'skipped') &&
(needs.publish-linux.result == 'success' || needs.publish-linux.result == 'skipped') &&
(needs.publish-macos.result == 'success' || needs.publish-macos.result == 'skipped') &&
(needs.publish-web.result == 'success' || needs.publish-web.result == 'skipped') &&
(needs.publish-windows.result == 'success' || needs.publish-windows.result == 'skipped')
needs: [ prepare, publish-android, publish-ios, publish-linux, publish-macos, publish-web, publish-s3 ]
uses: JagandeepBrar/LunaSea/.github/workflows/notify.yml@master
with:
flavor: ${{ github.event.inputs.flavor || 'edge' }}
build-changelog: ${{ needs.prepare.outputs.build-changelog }}
build-flavor: ${{ needs.prepare.outputs.build-flavor }}
build-title: ${{ needs.prepare.outputs.build-title }}
enable-android: ${{ needs.prepare.outputs.enable-android && needs.publish-android.result == 'success' }}
enable-ios: ${{ needs.prepare.outputs.enable-ios && needs.publish-ios.result == 'success' }}
enable-linux: ${{ needs.prepare.outputs.enable-linux && needs.publish-linux.result == 'success' }}
enable-macos: ${{ needs.prepare.outputs.enable-macos && needs.publish-macos.result == 'success' }}
enable-web: ${{ needs.prepare.outputs.enable-web && needs.publish-web.result == 'success' }}
enable-windows: ${{ needs.prepare.outputs.enable-windows && needs.publish-windows.result == 'success' }}
secrets:
DISCORD_WEBHOOK_EDGE: ${{ secrets.DISCORD_WEBHOOK_EDGE }}
DISCORD_WEBHOOK_BETA: ${{ secrets.DISCORD_WEBHOOK_BETA }}

View File

@@ -17,8 +17,11 @@ jobs:
firebase-token: ${{ secrets.FIREBASE_TOKEN }}
platform: test
- name: Analyze
- name: Analyze Release
uses: invertase/github-action-dart-analyzer@v1
with:
fatal-infos: false
fatal-warnings: true
- name: Test Release
run: flutter test

1
.gitignore vendored
View File

@@ -42,6 +42,7 @@ ios/Flutter/.last_build_id
output/
*.packages
coverage/
lib/system/environment.dart
# XCode Build Artifacts
ios/build/

View File

@@ -1 +1 @@
3.1.1
2.6.8

View File

@@ -24,5 +24,5 @@
"section": "Tweaks"
}
],
"releaseCommitMessageFormat": "chore(release): v{{currentTag}}\n\n[skip ci]"
"releaseCommitMessageFormat": "release: v{{currentTag}}\n\n[skip ci]"
}

5
.vscode/cspell.json vendored
View File

@@ -24,6 +24,7 @@
"cocoapods",
"codecov",
"colours",
"deinitialize",
"deintegrate",
"Discogs",
"emdash",
@@ -40,7 +41,10 @@
"leechers",
"Letterboxd",
"Lidarr",
"LunaBox",
"LunaConfig",
"lunasea",
"LunaTable",
"msix",
"Newznab",
"NZBGet",
@@ -58,6 +62,7 @@
"stickied",
"subheaders",
"Tautulli",
"TestFlight",
"Trakt",
"unencrypted",
"unignore",

34
.vscode/launch.json vendored
View File

@@ -1,13 +1,23 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Debug",
"request": "launch",
"type": "dart"
}
]
}
"version": "0.2.0",
"configurations": [
{
"name": "Debug",
"request": "launch",
"type": "dart",
"flutterMode": "debug"
},
{
"name": "Profile",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
{
"name": "Release",
"request": "launch",
"type": "dart",
"flutterMode": "release"
}
]
}

View File

@@ -1,5 +0,0 @@
{
"yaml.schemas": {
"https://json.schemastore.org/github-workflow.json": "file:///Users/jagandeepbrar/Git/LunaSea/.github/workflows/deploy.yml"
}
}

View File

@@ -2,6 +2,46 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [10.1.0](https://github.com/JagandeepBrar/LunaSea/compare/v10.0.3...v10.1.0) (2022-08-21)
### Features
* **calendar:** show current month in header ([925f163](https://github.com/JagandeepBrar/LunaSea/commit/925f163e1534aeb45e5b22e8254eaf391eabd79f))
* **changelog:** prepare and show changelog on pre-release builds ([df65f53](https://github.com/JagandeepBrar/LunaSea/commit/df65f53a4b00d11abc998f681274d22d94254f14))
* **locale:** support Vietnamese (vi) ([8b57450](https://github.com/JagandeepBrar/LunaSea/commit/8b5745044e3af64a6c9bc593a9877400ac8a2dc2))
### Bug Fixes
* **android:** correctly handle back-button to open drawer on applicable routes ([c91ba2c](https://github.com/JagandeepBrar/LunaSea/commit/c91ba2ce8134fdc796d0431ba1c9134908fddd91))
* **changelog:** group changelog item rows by key feature change ([2ababbd](https://github.com/JagandeepBrar/LunaSea/commit/2ababbd1b32abd153fa73fcdfe292c7791edbf52))
* **ci:** utilize latest standard for Snapcraft login ([aff6e2c](https://github.com/JagandeepBrar/LunaSea/commit/aff6e2ca184e9539f28dd326c06478ca2dbfee4c))
* **database:** correctly store manually ordered module list ([8fe81d1](https://github.com/JagandeepBrar/LunaSea/commit/8fe81d11ab5c5aa484f0c2b471932d5364e6209c))
* **database:** detect and recover from database corruption ([758756f](https://github.com/JagandeepBrar/LunaSea/commit/758756fcf2456996c7ee02be2bd523cca91c45d3))
* **database:** fallback to defaults on null values in profile ([fb3e8e5](https://github.com/JagandeepBrar/LunaSea/commit/fb3e8e53255c457d0922505ad6c2d91f5c0fcf03))
* **database:** safely type indexer fields and headers ([f1dcd0c](https://github.com/JagandeepBrar/LunaSea/commit/f1dcd0c36d558882bfbc7f4465ed56fac0743c55))
* **database:** utilize stricter typing for module headers map ([d4d9816](https://github.com/JagandeepBrar/LunaSea/commit/d4d9816c945b1930ecfda0382d809a7c67839a26))
* **database:** validate enabled profile exists on restore ([d8506ee](https://github.com/JagandeepBrar/LunaSea/commit/d8506ee2834ca6a83394c11f6d4d329f03a3647f))
* display 0-length timestamps as "0 Minutes" instead of "Under a Minute" ([e05b17a](https://github.com/JagandeepBrar/LunaSea/commit/e05b17ae5ed35cec85ade5b910b82869cb7ad3f2))
* **lidarr:** (history) sort list by date descending ([ad22820](https://github.com/JagandeepBrar/LunaSea/commit/ad22820d6662371d3d2bc7fbf596f86619002d20))
* **lists:** reorderable lists could not be reordered on some platforms ([95a645c](https://github.com/JagandeepBrar/LunaSea/commit/95a645c06cf2a76231c4b8dbea87ec593961c205))
* **locale:** create stub primary language localization assets ([18ef4cf](https://github.com/JagandeepBrar/LunaSea/commit/18ef4cf1d4032a3f9db54b5da56158ffaf9b50c8))
* **overseerr:** issues/requests list view translation keys ([136b92b](https://github.com/JagandeepBrar/LunaSea/commit/136b92b8a7bdd5cd0ec2322444443d054df6daed))
* **radarr:** (queue) allow loading queue list when associated movie is not found ([22bf728](https://github.com/JagandeepBrar/LunaSea/commit/22bf728a3dab6b7d76c7674cb4d97dc73e849201))
* **sonarr:** fanart image requests not including headers ([b5bb300](https://github.com/JagandeepBrar/LunaSea/commit/b5bb300046431d8c1c26fd8ac4a26c42444f4f53))
* **sonarr:** invalid linking to theTVDB content ([80678a7](https://github.com/JagandeepBrar/LunaSea/commit/80678a75bb871a4835d1c73934e043564d80b6b0))
### Tweaks
* **changelog:** do not show documentation changes in in-app changelog ([2367050](https://github.com/JagandeepBrar/LunaSea/commit/2367050a66f2929d1ead17cc9191f47ddcb07f3a))
* **core:** destructure core folder and reintegrate extensions ([5d52440](https://github.com/JagandeepBrar/LunaSea/commit/5d52440a43e4b605a8ac95bcb02b909f489ef7e2))
* **database:** rewrite interface to key-value database ([a0eaca0](https://github.com/JagandeepBrar/LunaSea/commit/a0eaca084a399a2e249b142cb720cc50739a3f51))
* **environment:** load environment using environment_config ([c4dd509](https://github.com/JagandeepBrar/LunaSea/commit/c4dd509e3210847c0ddba4c7982f38099228a2d6))
* refactored in-app purchase interface ([9cb3fab](https://github.com/JagandeepBrar/LunaSea/commit/9cb3fabdf1f5fa10d65770a181ced937413642a2))
* utilize statics and class functions for LunaModule enum ([9f3c3f7](https://github.com/JagandeepBrar/LunaSea/commit/9f3c3f779dda1b2da007abe5c2079dcfa834eb99))
### [10.0.3](https://github.com/JagandeepBrar/LunaSea/compare/v10.0.2...v10.0.3) (2022-05-26)

View File

@@ -3,7 +3,7 @@
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-29-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-35-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
@@ -50,6 +50,14 @@ Thank you to everyone who has helped contribute to LunaSea, from development to
<td align="center"><a href="https://github.com/neoestremi"><img src="https://avatars.githubusercontent.com/u/1340877?v=4?s=100" width="100px;" alt=""/><br /><sub><b>neoestremi</b></sub></a><br /><a href="#translation-neoestremi" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/marcosvdiasofc"><img src="https://avatars.githubusercontent.com/u/96720080?v=4?s=100" width="100px;" alt=""/><br /><sub><b>marcosvdiasofc</b></sub></a><br /><a href="#translation-marcosvdiasofc" title="Translation">🌍</a></td>
<td align="center"><a href="https://liberapay.com/FSCorrupt/donate"><img src="https://avatars.githubusercontent.com/u/45659314?v=4?s=100" width="100px;" alt=""/><br /><sub><b>FSCorrupt</b></sub></a><br /><a href="#translation-fscorrupt" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/iHunterX"><img src="https://avatars.githubusercontent.com/u/16854718?v=4?s=100" width="100px;" alt=""/><br /><sub><b>iHunterX</b></sub></a><br /><a href="#translation-iHunterX" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/Brokeos"><img src="https://avatars.githubusercontent.com/u/8388746?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Brokeos</b></sub></a><br /><a href="#translation-Brokeos" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/punchy98"><img src="https://avatars.githubusercontent.com/u/12002902?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Michael Maldonado</b></sub></a><br /><a href="#translation-punchy98" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/natiz"><img src="https://avatars.githubusercontent.com/u/3515888?v=4?s=100" width="100px;" alt=""/><br /><sub><b>natiz</b></sub></a><br /><a href="https://github.com/JagandeepBrar/LunaSea/commits?author=natiz" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/KevoM"><img src="https://avatars.githubusercontent.com/u/8274366?v=4?s=100" width="100px;" alt=""/><br /><sub><b>KevoM</b></sub></a><br /><a href="#translation-KevoM" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/rogeriomendes"><img src="https://avatars.githubusercontent.com/u/1494503?v=4?s=100" width="100px;" alt=""/><br /><sub><b>rogeriomendes</b></sub></a><br /><a href="#translation-rogeriomendes" title="Translation">🌍</a></td>
</tr>
</table>

View File

@@ -8,20 +8,20 @@ GEM
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.587.0)
aws-sdk-core (3.130.2)
aws-partitions (1.618.0)
aws-sdk-core (3.132.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-kms (1.56.0)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.58.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.114.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.0)
aws-sigv4 (1.5.1)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.1.0)
@@ -34,10 +34,10 @@ GEM
rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.6)
dotenv (2.8.1)
emoji_regex (3.2.3)
excon (0.92.3)
faraday (1.10.0)
excon (0.92.4)
faraday (1.10.1)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
@@ -56,8 +56,8 @@ GEM
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.3)
multipart-post (>= 1.2, < 3)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
@@ -66,7 +66,7 @@ GEM
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.6)
fastlane (2.205.2)
fastlane (2.209.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
@@ -106,9 +106,9 @@ GEM
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.20.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-core (0.4.2)
google-apis-androidpublisher_v3 (0.25.0)
google-apis-core (>= 0.7, < 2.a)
google-apis-core (0.7.0)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@@ -117,27 +117,27 @@ GEM
retriable (>= 2.0, < 4.a)
rexml
webrick
google-apis-iamcredentials_v1 (0.10.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-playcustomapp_v1 (0.7.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-storage_v1 (0.13.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-iamcredentials_v1 (0.13.0)
google-apis-core (>= 0.7, < 2.a)
google-apis-playcustomapp_v1 (0.10.0)
google-apis-core (>= 0.7, < 2.a)
google-apis-storage_v1 (0.17.0)
google-apis-core (>= 0.7, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.2.0)
google-cloud-storage (1.36.2)
google-cloud-storage (1.38.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.17.0)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.1.3)
googleauth (1.2.0)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
@@ -145,12 +145,12 @@ GEM
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
highline (2.0.3)
http-cookie (1.0.4)
http-cookie (1.0.5)
domain_name (~> 0.5)
httpclient (2.8.3)
jmespath (1.6.1)
json (2.6.1)
jwt (2.3.0)
json (2.6.2)
jwt (2.4.1)
memoist (0.16.2)
mini_magick (4.11.0)
mini_mime (1.1.2)
@@ -163,7 +163,7 @@ GEM
plist (3.6.0)
public_suffix (4.0.7)
rake (13.0.6)
representable (3.1.1)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
@@ -173,9 +173,9 @@ GEM
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
security (0.1.3)
signet (0.16.1)
signet (0.17.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.0)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.8)
@@ -192,11 +192,11 @@ GEM
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.1)
unf_ext (0.0.8.2)
unicode-display_width (1.8.0)
webrick (1.7.0)
word_wrap (1.0.0)
xcodeproj (1.21.0)
xcodeproj (1.22.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
@@ -209,10 +209,10 @@ GEM
xcpretty (~> 0.2, >= 0.0.7)
PLATFORMS
x86_64-darwin-21
ruby
DEPENDENCIES
fastlane
BUNDLED WITH
2.3.10
2.3.19

View File

@@ -29,7 +29,7 @@ Build App Bundle
[bundle exec] fastlane android build_apk
```
Build APKs
Build APK
### android deploy_playstore

View File

@@ -1,3 +0,0 @@
Thank you for testing upcoming releases of LunaSea! Please consider joining the Discord to give feedback to the developer.
Changes can be found on GitHub or by going to settings/system and tapping on the version tile!

View File

@@ -1,49 +1 @@
{
"motd": "This release is the first build to be built on Flutter 3, which now supports 120hz displays and is more performant across the board!",
"new": [
{
"module": "-arr",
"changes": [
"(Details) Updated UI for viewing content links"
]
},
{
"module": "LunaSea",
"changes": [
"Support 120hz displays"
]
},
{
"module": "Notifications",
"changes": [
"Option to disable in-app notifications"
]
},
{
"module": "Radarr",
"changes": [
"(Links) Added Letterboxd"
]
},
{
"module": "Settings",
"changes": [
"(System) Ability to check for updates"
]
}
],
"fixes": [
{
"module": "-arr",
"changes": [
"(Releases) Correctly calculate age of releases"
]
},
{
"module": "UI/UX",
"changes": [
"(Scrollbar) Enable interactivity on all platforms"
]
}
]
}
{}

View File

@@ -1,27 +0,0 @@
{
"motd": "",
"new": [
{
"module": "",
"changes": [
""
]
}
],
"tweaks": [
{
"module": "",
"changes": [
""
]
}
],
"fixes": [
{
"module": "",
"changes": [
""
]
}
]
}

View File

@@ -0,0 +1,97 @@
{
"motd": "Welcome to LunaSea v10.1.0!\n\nThis release contains a wide variety of bug fixes including a completely rewritten database interface to detect and be resilient against corruption.",
"feat": {
"changelog": [
{
"commit": "df65f53a4b00d11abc998f681274d22d94254f14",
"message": "prepare and show changelog on pre-release builds"
}
],
"calendar": [
{
"commit": "925f163e1534aeb45e5b22e8254eaf391eabd79f",
"message": "show current month in header"
}
]
},
"fix": {
"database": [
{
"commit": "8fe81d11ab5c5aa484f0c2b471932d5364e6209c",
"message": "correctly store manually ordered module list"
},
{
"commit": "758756fcf2456996c7ee02be2bd523cca91c45d3",
"message": "detect and recover from database corruption"
},
{
"commit": "fb3e8e53255c457d0922505ad6c2d91f5c0fcf03",
"message": "fallback to defaults on null values in profile"
},
{
"commit": "f1dcd0c36d558882bfbc7f4465ed56fac0743c55",
"message": "safely type indexer fields and headers"
},
{
"commit": "d4d9816c945b1930ecfda0382d809a7c67839a26",
"message": "utilize stricter typing for module headers map"
},
{
"commit": "d8506ee2834ca6a83394c11f6d4d329f03a3647f",
"message": "validate enabled profile exists on restore"
}
],
"sonarr": [
{
"commit": "b5bb300046431d8c1c26fd8ac4a26c42444f4f53",
"message": "fanart image requests did not including headers"
},
{
"commit": "80678a75bb871a4835d1c73934e043564d80b6b0",
"message": "invalid links to theTVDB content"
}
],
"lidarr": [
{
"commit": "ad22820d6662371d3d2bc7fbf596f86619002d20",
"message": "(history) sort list by date descending"
}
],
"radarr": [
{
"commit": "22bf728a3dab6b7d76c7674cb4d97dc73e849201",
"message": "(queue) allow loading queue list when associated movie is not found"
}
],
"android": [
{
"commit": "c91ba2ce8134fdc796d0431ba1c9134908fddd91",
"message": "correctly handle back-button to open drawer on applicable routes"
}
],
"ui/ux": [
{
"commit": "95a645c06cf2a76231c4b8dbea87ec593961c205",
"message": "(lists) reorderable lists could not be reordered on some platforms"
},
{
"commit": "e05b17ae5ed35cec85ade5b910b82869cb7ad3f2",
"message": "(timestamps) display 0-length timestamps as \"0 Minutes\" instead of \"Under a Minute\""
}
]
},
"refactor": {
"purchases": [
{
"commit": "9cb3fabdf1f5fa10d65770a181ced937413642a2",
"message": "rewrite interface to in-app purchase APIs"
}
],
"database": [
{
"commit": "a0eaca084a399a2e249b142cb720cc50739a3f51",
"message": "rewrite interface to key-value database"
}
]
}
}

View File

@@ -61,7 +61,6 @@
"lunasea.New": "Neu",
"lunasea.NoModulesEnabled": "Keine Module aktiviert",
"lunasea.NotSet": "Nicht gesetzt",
"lunasea.OneHourAgo": "Vor einer Stunde",
"lunasea.Options": "Optionen",
"lunasea.Page": "Seite",
"lunasea.PlatformSpecific": "Plattformspezifisch",

View File

@@ -36,41 +36,63 @@
"lunasea.Changelog": "Changelog",
"lunasea.ChangeProfiles": "Change Profiles",
"lunasea.CheckLogsMessage": "Check the logs for more details",
"lunasea.Chores": "Chores",
"lunasea.Clear": "Clear",
"lunasea.Close": "Close",
"lunasea.ComingSoon": "Coming Soon",
"lunasea.Copied": "Copied",
"lunasea.CopiedContentToTheClipboard": "Copied Content to the Clipboard",
"lunasea.Critical": "Critical",
"lunasea.Dashboard": "Dashboard",
"lunasea.Days": "{} Days",
"lunasea.DaysAgo": "{} Days Ago",
"lunasea.Debug": "Debug",
"lunasea.Delete": "Delete",
"lunasea.Descending": "Descending",
"lunasea.Develop": "Develop",
"lunasea.Disable": "Disable",
"lunasea.Disabled": "Disabled",
"lunasea.Dismiss": "Dismiss",
"lunasea.Docs": "Docs",
"lunasea.Edge": "Edge",
"lunasea.Error": "Error",
"lunasea.ExternalModules": "External Modules",
"lunasea.Features": "Features",
"lunasea.Fixes": "Fixes",
"lunasea.FullChangelog": "Full Changelog",
"lunasea.GoBack": "Go Back",
"lunasea.GoToSettings": "Go to Settings",
"lunasea.GridView": "Grid View",
"lunasea.Home": "Home",
"lunasea.Hours": "{} Hours",
"lunasea.HoursAgo": "{} Hours Ago",
"lunasea.IncorrectEncryptionKey": "Incorrect encryption key",
"lunasea.Internal": "Internal",
"lunasea.InvalidFileTypeSelected": "Invalid File Type Selected",
"lunasea.JustNow": "Just Now",
"lunasea.Minutes": "{} Minutes",
"lunasea.MinutesAgo": "{} Minutes Ago",
"lunasea.Module": "Module",
"lunasea.ModuleIsNotEnabled": "{} Is Not Enabled",
"lunasea.Months": "{} Months",
"lunasea.MonthsAgo": "{} Months Ago",
"lunasea.New": "New",
"lunasea.NotSet": "Not Set",
"lunasea.NoModulesEnabled": "No Modules Enabled",
"lunasea.OneDay": "1 Day",
"lunasea.OneDayAgo": "1 Day Ago",
"lunasea.OneHour": "1 Hour",
"lunasea.OneHourAgo": "1 Hour Ago",
"lunasea.OneMinute": "1 Minute",
"lunasea.OneMinuteAgo": "1 Minute Ago",
"lunasea.OneMonth": "1 Month",
"lunasea.OneMonthAgo": "1 Month Ago",
"lunasea.OneSecond": "1 Second",
"lunasea.OneSecondAgo": "1 Second Ago",
"lunasea.OneYear": "1 Year",
"lunasea.OneYearAgo": "1 Year Ago",
"lunasea.Options": "Options",
"lunasea.Other": "Other",
"lunasea.Page": "Page",
"lunasea.PlatformSpecific": "Platform-Specific",
"lunasea.PleaseTryAgain": "Please Try Again",
@@ -83,19 +105,27 @@
"lunasea.Retry": "Retry",
"lunasea.ReturnToDashboard": "Return to Dashboard",
"lunasea.SearchTextBar": "Search…",
"lunasea.Seconds": "{} Seconds",
"lunasea.SecondsAgo": "{} Seconds Ago",
"lunasea.Set": "Set",
"lunasea.Settings": "Settings",
"lunasea.Stable": "Stable",
"lunasea.StartingView": "Starting View",
"lunasea.Today": "Today",
"lunasea.TransactionFailure": "Transaction Failure",
"lunasea.TryAgain": "Try Again",
"lunasea.Tweaks": "Tweaks",
"lunasea.UnderAMinute": "Under a Minute",
"lunasea.Unknown": "Unknown",
"lunasea.UnknownDate": "Unknown Date",
"lunasea.UnknownError": "Unknown Error",
"lunasea.UnknownModule": "Unknown Module",
"lunasea.Update": "Update",
"lunasea.View": "View",
"lunasea.Warning": "Warning",
"lunasea.Website": "Website",
"lunasea.Years": "{} Years",
"lunasea.YearsAgo": "{} Years Ago",
"overseerr.Audio": "Audio",
"overseerr.Approved": "Approved",
"overseerr.Available": "Available",
@@ -280,6 +310,7 @@
"settings.AddModuleSuccess": "Module Added",
"settings.AddProfile": "Add Profile",
"settings.AddProfileDescription": "Add a New Profile",
"settings.AddedProfile": "Added Profile",
"settings.AllFieldsAreRequired": "All fields are required",
"settings.AmoledTheme": "AMOLED Theme",
"settings.AmoledThemeBorders": "AMOLED Theme Borders",
@@ -318,6 +349,7 @@
"settings.BuildChannels": "Build Channels",
"settings.BuildChannelsDescription": "Learn About Additional Build Channels",
"settings.CalendarSettings": "Calendar Settings",
"settings.ChangedProfile": "Changed Profile",
"settings.Channel": "Channel",
"settings.ClearConfiguration": "Clear Configuration",
"settings.ClearConfigurationHint1": "Are you sure you want to clear your configuration?",
@@ -341,6 +373,9 @@
"settings.CustomHeader": "Custom Header",
"settings.CustomHeaders": "Custom Headers",
"settings.CustomHeadersDescription": "Add Custom Headers to Requests",
"settings.DatabaseCorruptionDetected": "Database Corruption Detected",
"settings.DatabaseCorruptionDetectedMessageLine1": "Database corruption has been detected and your configuration has been cleared.",
"settings.DatabaseCorruptionDetectedMessageLine2": "Sorry about the inconvenience, all previously created backups should be restorable even when previously exported with a corrupted database.",
"settings.DaysOne": "1 Day",
"settings.DaysCount": "{} Days",
"settings.DefaultPage": "Default Page",
@@ -354,6 +389,7 @@
"settings.DecryptBackupHint1": "Please enter the encryption key for this backup.",
"settings.DebugMenu": "Debug Menu",
"settings.DebugMenuDescription": "Debug and Development Utilities",
"settings.DeletedProfile": "Deleted Profile",
"settings.DeleteAccount": "Delete Account",
"settings.DeleteAccountDescription": "Permanently Delete Your Account",
"settings.DeleteAccountHint1": "Are you sure you want to delete your LunaSea account?",
@@ -444,9 +480,11 @@
"settings.NewPassword": "New Password",
"settings.Notifications": "Notifications",
"settings.NotificationsDescription": "Set up Webhooks for Push Notifications",
"settings.NoAdditionalProfilesAdded": "No additional profiles have been added",
"settings.NoBackupsFound": "No Backups Found",
"settings.NoExternalModulesFound": "No External Modules Found",
"settings.NoHeadersAdded": "No Headers Added",
"settings.NoProfilesFound": "No Profiles Found",
"settings.OpenLinksIn": "Open Links In…",
"settings.Password": "Password",
"settings.PasswordHint1": "If your password includes special characters, considering adding a basic authentication header with your username and password instead for better support",
@@ -463,6 +501,7 @@
"settings.ProfileAlreadyExists": "Profile Already Exists",
"settings.ProfileName": "Profile Name",
"settings.ProfileNameRequired": "Profile Name Required",
"settings.ProfileToProfile": "\"{}\" to \"{}\"",
"settings.QuickActions": "Quick Actions",
"settings.QuickActionsDescription": "Quick Actions on the Home Screen",
"settings.QuickActionsBannerLine1": "Quick actions allow you to quickly jump into modules directly from the home screen or launcher on your device by long pressing LunaSea's icon.",
@@ -471,6 +510,7 @@
"settings.Register": "Register",
"settings.RegisteredFailure": "Failed to Register",
"settings.RegisteredSuccess": "Registered",
"settings.RenamedProfile": "Renamed Profile",
"settings.RenameProfile": "Rename Profile",
"settings.RenameProfileDescription": "Rename an Existing Profile",
"settings.ResetPassword": "Reset Password",
@@ -514,6 +554,7 @@
"settings.UsernameValidation": "Username Required",
"settings.Version": "Version",
"settings.ViewRecentChanges": "View Recent Changes",
"settings.ViewTypeLogs": "View {} Logs",
"settings.WeblateDescription": "Help Localize LunaSea",
"settings.Website": "Website",
"settings.WebsiteDescription": "Visit LunaSea's Website",

View File

@@ -18,22 +18,51 @@
"dashboard.Monday": "Lunes",
"dashboard.NoNewContent": "No contenido nuevo",
"dashboard.OneMonth": "Un mes",
"lidarr.StartSearchFor": "Iniciar búsqueda de…",
"lidarr.StartSearchForMissingAlbums": "Iniciar la búsqueda de álbumes que faltan",
"lunasea.Add": "Añadir",
"lunasea.Alpha": "Alfa",
"lunasea.AnErrorHasOccurred": "Se ha producido un error",
"lunasea.Ascending": "Ascendente",
"lunasea.BackUp": "Respaldar",
"lunasea.Beta": "Beta",
"lunasea.BlockView": "Vista de bloque",
"lunasea.BuyMeABeer": "Cómprame una cerveza",
"lunasea.BuyMeABurger": "Cómprame una hamburguesa",
"lunasea.BuyMeACoffee": "cómprame un café",
"lunasea.BuyMeASoda": "Cómprame un refresco",
"lunasea.Cancel": "Cancelar",
"lunasea.Candidate": "Candidato",
"lunasea.ChangeProfiles": "Cambiar perfiles",
"lunasea.Changelog": "Registro de cambios",
"lunasea.CheckLogsMessage": "Consulte los registros para más detalles",
"lunasea.Chores": "Quehaceres",
"lunasea.Clear": "Borrar",
"lunasea.Close": "Cerrar",
"lunasea.ComingSoon": "Próximamente",
"lunasea.Copied": "Copiado",
"lunasea.CopiedContentToTheClipboard": "Contenido copiado en el portapapeles",
"lunasea.Critical": "Crítica",
"lunasea.Dashboard": "Tablero",
"lunasea.Days": "{} Días",
"lunasea.DaysAgo": "{} Hace días",
"lunasea.Debug": "Depurar",
"lunasea.Delete": "Eliminar",
"lunasea.Descending": "Descendente",
"lunasea.Develop": "Desarrollar",
"lunasea.Disable": "Desactivar",
"lunasea.Disabled": "Desactivado",
"lunasea.Dismiss": "Descartar",
"lunasea.Docs": "Documentos",
"lunasea.Edge": "Borde",
"lunasea.Error": "Error",
"lunasea.ExternalModules": "Módulos externos",
"lunasea.Features": "Características",
"lunasea.Fixes": "Arreglos",
"lunasea.FullChangelog": "Registro completo de cambios",
"lunasea.GoBack": "Regresar",
"lunasea.GoToSettings": "Ve a Configuración",
"lunasea.GridView": "Vista de cuadrícula",
"lunasea.IncorrectEncryptionKey": "Clave de cifrado incorrecta",
"lunasea.Module": "Módulo",
"lunasea.ModuleIsNotEnabled": "{} No está habilitado",
@@ -62,16 +91,21 @@
"overseerr.Users": "Usuarios",
"radarr.AddMovie": "Añadir película",
"radarr.AddMovieAndSearch": "Añadir y Buscar",
"radarr.AddedTag": "Etiqueta añadida",
"radarr.Age": "Edad",
"radarr.All": "Todo",
"radarr.Alphabetical": "Alfabético",
"radarr.Approved": "Aprobado",
"radarr.Audio": "Audio",
"radarr.Automatic": "Automático",
"radarr.AvailabilityUnknown": "Disponibilidad desconocida",
"radarr.AvailableIn": "Disponible en {}",
"radarr.AvailableToday": "Disponible hoy",
"radarr.BackupDatabase": "Respaldar base de datos",
"radarr.BitDepth": "Profundidad de bits",
"radarr.Channels": "Canales",
"radarr.CinemaDateUnknown": "Fecha de cine desconocida",
"radarr.Codec": "Códec",
"radarr.Configure": "Configurar",
"radarr.Copy": "Copiar",
"radarr.CopyFull": "Enlazar/Copiar archivos",
@@ -80,9 +114,13 @@
"radarr.DigitalRelease": "Publicación digital",
"radarr.DirectoryNotFound": "Directorio no encontrado",
"radarr.Discover": "Descubra",
"radarr.Disks": "Discos",
"radarr.DownloadFailed": "Descarga fracasó",
"radarr.DownloadIgnored": "Descarga ignorada",
"radarr.DynamicRange": "Rango dinámico",
"radarr.EditMovie": "Editar película",
"radarr.FPS": "FPS",
"radarr.FailedToAddTag": "Error al agregar etiqueta",
"radarr.FileBrowser": "Explorador de archivos…",
"radarr.FilterCatalogue": "Catálogo de filtros",
"radarr.GrabbedFrom": "Tomada de {}",
@@ -100,6 +138,7 @@
"radarr.ManualImportDescription": "Importar películas desde el sistema de archivos",
"radarr.MinimumAvailability": "Disponibilidad mínima",
"radarr.Missing": "Falta",
"radarr.Monitor": "Monitor",
"radarr.MonitorMovie": "Monitorear película",
"radarr.Monitored": "Monitoreada",
"radarr.MonitoredDescription": "Monitorear nuevos lanzamientos",
@@ -113,12 +152,16 @@
"radarr.MovieNotFound": "Película no encontrada",
"radarr.MoviePath": "Ruta de la película",
"radarr.Movies": "Películas",
"radarr.NoDisksFound": "No se han encontrado discos",
"radarr.NoFilesFound": "No se encontraron archivos",
"radarr.NoHistoryFound": "No se encontró historial",
"radarr.NoMoviesFound": "No se encontraron películas",
"radarr.NoResultsFound": "No se encontraron resultados",
"radarr.NoRootFoldersFound": "No se han encontrado carpetas raíz",
"radarr.NoSubdirectoriesFound": "No se encontraron subdirectorios",
"radarr.NoSummaryIsAvailable": "No hay resumen disponible.",
"radarr.NoTagsFound": "No se han encontrado etiquetas",
"radarr.Other": "Otro",
"radarr.ParentDirectory": "Directorio principal",
"radarr.PhysicalRelease": "Estreno Físico",
"radarr.Quality": "Calidad",
@@ -130,10 +173,14 @@
"radarr.Rejected": "Rechazado",
"radarr.Released": "Estrenada",
"radarr.ReleasedToday": "Estrena hoy",
"radarr.Releases": "Comunicados",
"radarr.RemoveMovie": "Eliminar película",
"radarr.Resolution": "Resolución",
"radarr.RootFolder": "Carpeta raíz",
"radarr.RootFolders": "Carpetas raíz",
"radarr.RunRSSSync": "Ejecutar sincronización RSS",
"radarr.Runtime": "Duración",
"radarr.ScanType": "Tipo de escáner",
"radarr.Search": "Buscar",
"radarr.SearchAllMissing": "Búsqueda que falta",
"radarr.SearchFor": "Buscar {}",
@@ -143,17 +190,24 @@
"radarr.SelectQuality": "Seleccionar calidad",
"radarr.Size": "Tamaño",
"radarr.SortCatalogue": "Ordenar catálogo",
"radarr.StartSearchFor": "Iniciar la búsqueda de…",
"radarr.StartSearchForMissingMovie": "Iniciar la búsqueda de la película perdida",
"radarr.Streams": "Arroyos",
"radarr.Studio": "Estudio",
"radarr.Subtitles": "Subtítulos",
"radarr.SystemStatus": "Estado del sistema",
"radarr.SystemStatusDescription": "Estado del sistema y tamaño de disco",
"radarr.Tags": "Etiquetas",
"radarr.TagsDescription": "Administre sus etiquetas",
"radarr.Type": "Tipo",
"radarr.UnmappedFolder": "1 Carpeta sin mapear",
"radarr.UnmappedFolders": "{} Carpetas no asignadas",
"radarr.UnmonitorMovie": "No monitorear",
"radarr.Unmonitored": "No monitoreadas",
"radarr.Upcoming": "Próximamente",
"radarr.UpdateLibrary": "Actualizar librería",
"radarr.UpdateMovie": "Actualizar película",
"radarr.Video": "Vídeo",
"radarr.ViewWebGUI": "Ver GUI web",
"radarr.Wanted": "Se busca",
"radarr.Weight": "Peso",
@@ -349,6 +403,22 @@
"settings.RestoreFromCloudDescription": "Restaurar datos de configuración",
"settings.RestoreFromCloudFailure": "Falló la restauración",
"settings.BannersNotificationModuleSupportBody": "Actualmente, las notificaciones basadas en webhook solo se admiten en los módulos que se enumeran a continuación.\n\n¡El soporte para módulos adicionales vendrá en el futuro!",
"settings.AccountDeleted": "Cuenta borrada",
"settings.AccountSettings": "Configuración de la cuenta",
"settings.BuildChannels": "Construir canales",
"settings.BuildChannelsDescription": "Aprender acerca de canales adicionales de construir",
"settings.Add": "Añadir",
"settings.AddProfileDescription": "Añadir un nuevo perfil",
"settings.AddedProfile": "Perfil añadido",
"settings.ChangedProfile": "Perfil cambiado",
"settings.ClearImageCacheHint1": "¿Estás seguro de que quieres borrar todas las imágenes de la caché?",
"settings.ClearImageCache": "Borrar la caché de imágenes",
"settings.BackupToDevice": "Copia de seguridad en el dispositivo",
"settings.BackupToDeviceDescription": "Copia de seguridad de los datos de configuración",
"settings.CalendarSettings": "Configuración del calendario",
"settings.AccountDeletedMessage": "Borrado su cuenta de LunaSea",
"settings.Channel": "Canal",
"settings.Build": "Construir",
"tautulli.Quality": "Calidad",
"tautulli.None": "Ninguno",
"tautulli.Terminate": "Terminar",
@@ -416,5 +486,8 @@
"tautulli.Throttled": "Acelerado",
"tautulli.Transcode": "Transcodificar",
"tautulli.Transcodes": "Transcodificaciones",
"tautulli.ETA": "Tiempo Restante"
"tautulli.ETA": "Tiempo Restante",
"wake_on_lan.MagicPacketSent": "Paquete mágico enviado",
"wake_on_lan.MagicPacketSentMessage": "¡Su máquina debería estar despertando!",
"wake_on_lan.MagicPacketFailedToSend": "Error al enviar Magic Packet"
}

View File

@@ -34,38 +34,65 @@
"lunasea.Cancel": "Annuler",
"lunasea.Candidate": "Candidat",
"lunasea.ChangeProfiles": "Changer de profil",
"lunasea.Changelog": "Changements",
"lunasea.CheckLogsMessage": "Vérifier les journaux pour plus de détails",
"lunasea.Chores": "Tâches",
"lunasea.Clear": "Nettoyer",
"lunasea.Close": "Fermer",
"lunasea.ComingSoon": "Prochainement",
"lunasea.Copied": "Copié",
"lunasea.CopiedContentToTheClipboard": "Contenu copié dans le presse-papiers",
"lunasea.Critical": "Critique",
"lunasea.Dashboard": "Tableau de bord",
"lunasea.Days": "{} Jours",
"lunasea.DaysAgo": "Il y a {} jours",
"lunasea.Debug": "Debug",
"lunasea.Delete": "Supprimer",
"lunasea.Descending": "Décroissant",
"lunasea.Develop": "Développer",
"lunasea.Disable": "Désactiver",
"lunasea.Disabled": "Désactivé",
"lunasea.Dismiss": "Rejeter",
"lunasea.Docs": "Documents",
"lunasea.Edge": "Limite",
"lunasea.Error": "Erreur",
"lunasea.ExternalModules": "Modules externes",
"lunasea.Features": "Fonctionnalités",
"lunasea.Fixes": "Corrections",
"lunasea.FullChangelog": "Liste complète des changements",
"lunasea.GoBack": "Retour en arrière",
"lunasea.GoToSettings": "Ouvrir les paramètres",
"lunasea.GridView": "Vue en grille",
"lunasea.Home": "Accueil",
"lunasea.Hours": "{} Heures",
"lunasea.HoursAgo": "Il y a {} heures",
"lunasea.IncorrectEncryptionKey": "Clé de chiffrement incorrecte",
"lunasea.Internal": "Interne",
"lunasea.InvalidFileTypeSelected": "Type de fichier sélectionné invalide",
"lunasea.JustNow": "À l'instant",
"lunasea.Minutes": "{} Minutes",
"lunasea.MinutesAgo": "Il y a {} minutes",
"lunasea.Module": "Module",
"lunasea.ModuleIsNotEnabled": "{} n'est pas activé",
"lunasea.Months": "{} Mois",
"lunasea.MonthsAgo": "Il y a {} mois",
"lunasea.New": "Nouveau",
"lunasea.NoModulesEnabled": "Aucun module activé",
"lunasea.NotSet": "Non défini",
"lunasea.OneHourAgo": "Il y a une heure",
"lunasea.OneDay": "1 Jour",
"lunasea.OneDayAgo": "Il y a 1 jour",
"lunasea.OneHour": "1 Heure",
"lunasea.OneHourAgo": "Il y a 1 heure",
"lunasea.OneMinute": "1 Minute",
"lunasea.OneMinuteAgo": "Il y a 1 minute",
"lunasea.OneMonth": "1 mois",
"lunasea.OneMonthAgo": "Il y a 1 mois",
"lunasea.OneSecond": "1 Seconde",
"lunasea.OneSecondAgo": "Il y a 1 seconde",
"lunasea.OneYear": "1 année",
"lunasea.OneYearAgo": "Il y a 1 année",
"lunasea.Options": "Options",
"lunasea.Other": "Autre",
"lunasea.Page": "Page",
"lunasea.PlatformSpecific": "Spécifique à la plateforme",
"lunasea.PleaseTryAgain": "Veuillez réessayer",
@@ -78,19 +105,27 @@
"lunasea.Retry": "Réessayer",
"lunasea.ReturnToDashboard": "Retour au tableau de bord",
"lunasea.SearchTextBar": "Rechercher…",
"lunasea.Seconds": "{} Secondes",
"lunasea.SecondsAgo": "Il y a {} Secondes",
"lunasea.Set": "Définir",
"lunasea.Settings": "Réglages",
"lunasea.Stable": "Stable",
"lunasea.StartingView": "Page d'accueil",
"lunasea.Today": "Aujourd'hui",
"lunasea.TransactionFailure": "Transaction échouée",
"lunasea.TryAgain": "Réessayer",
"lunasea.Tweaks": "Ajustements",
"lunasea.UnderAMinute": "Moins d'une Minute",
"lunasea.Unknown": "Inconnu",
"lunasea.UnknownDate": "Date inconnue",
"lunasea.UnknownError": "Erreur inconnue",
"lunasea.UnknownModule": "Module inconnu",
"lunasea.Update": "Mettre à jour",
"lunasea.View": "Vue",
"lunasea.Warning": "Attention",
"lunasea.Website": "Site web",
"lunasea.Years": "{} années",
"lunasea.YearsAgo": "Il y a {} années",
"overseerr.Users": "Utilisateurs",
"overseerr.UnknownUser": "Utilisateur inconnu",
"overseerr.NoUsersFound": "Aucun utilisateur trouvé",
@@ -507,6 +542,21 @@
"settings.UpdateEmail": "Modifier le courriel",
"settings.BuildChannels": "Canal de compilation",
"settings.BuildChannelsDescription": "En savoir plus sur les canaux de compilation",
"settings.AddedProfile": "Profils ajoutés",
"settings.Channel": "Canal",
"settings.DeletedProfile": "Profil supprimé",
"settings.DownloadUpdate": "Télécharger la mise à jour",
"settings.EnableInAppNotifications": "Activer les notifications In-App",
"settings.NoAdditionalProfilesAdded": "Aucun profil supplémentaire n'a été ajouté",
"settings.ProfileToProfile": "\"{}\" à \"{}\"",
"settings.UpToDate": "A jour",
"settings.ViewTypeLogs": "Voir {} journaux",
"settings.ChangedProfile": "Profil modifié",
"settings.Build": "Compilation",
"settings.NoProfilesFound": "Aucun profil trouvé",
"settings.RenamedProfile": "Profil renommé",
"settings.Platform": "Plateforme",
"settings.Version": "Version",
"sonarr.AddedOn": "Ajouté le",
"sonarr.AddedSeries": "Série ajoutée",
"sonarr.AddedTag": "Étiquette ajoutée",

View File

@@ -64,7 +64,6 @@
"lunasea.New": "Új",
"lunasea.NoModulesEnabled": "Nincs engedélyezett modul",
"lunasea.NotSet": "Nincs beállítva",
"lunasea.OneHourAgo": "1 órával ezelőtt",
"lunasea.Options": "Opciók",
"lunasea.Page": "Oldal",
"lunasea.PlatformSpecific": "Platform-specifikus",

View File

@@ -62,7 +62,6 @@
"lunasea.New": "Nuovo",
"lunasea.NoModulesEnabled": "Nessun modulo abilitato",
"lunasea.NotSet": "Non impostato",
"lunasea.OneHourAgo": "1 ora fa",
"lunasea.Options": "Opzioni",
"lunasea.Page": "Pagina",
"lunasea.PlatformSpecific": "Specifico della piattaforma",

View File

@@ -59,7 +59,6 @@
"lunasea.New": "Ny",
"lunasea.NoModulesEnabled": "Ingen påslåtte moduler",
"lunasea.NotSet": "Ikke satt",
"lunasea.OneHourAgo": "Én time siden",
"lunasea.Options": "Innstillinger",
"lunasea.Page": "Side",
"lunasea.PlatformSpecific": "Plattformsspesifikk",

View File

@@ -0,0 +1 @@
{}

View File

@@ -19,45 +19,104 @@
"dashboard.Friday": "Sexta-feira",
"dashboard.Calendar": "Calendário",
"lunasea.Add": "Adicionar",
"lunasea.Alpha": "Alpha",
"lunasea.AnErrorHasOccurred": "Ocorreu um erro",
"lunasea.Ascending": "Ascendente",
"lunasea.BackUp": "Back Up",
"lunasea.Beta": "Beta",
"lunasea.BlockView": "Visualização em bloco",
"lunasea.BuyMeABeer": "Compre-me uma cerveja",
"lunasea.BuyMeABurger": "Compre-me um hambúrguer",
"lunasea.BuyMeACoffee": "Compre-me um café",
"lunasea.BuyMeASoda": "Compre-me um refrigerante",
"lunasea.Cancel": "Cancelar",
"lunasea.ChangeProfiles": "Mudar de Perfil",
"lunasea.Changelog": "Alterações",
"lunasea.CheckLogsMessage": "Verifique os registos para mais detalhes",
"lunasea.Clear": "Limpar",
"lunasea.Close": "Fechar",
"lunasea.ComingSoon": "Em Breve",
"lunasea.Copied": "Copiado",
"lunasea.CopiedContentToTheClipboard": "Conteúdo copiado para a área de transferência",
"lunasea.Critical": "Crítico",
"lunasea.Dashboard": "Painel de Controle",
"lunasea.Days": "{} Dias",
"lunasea.DaysAgo": "{} Dias atrás",
"lunasea.Debug": "Depurar",
"lunasea.Delete": "Eliminar",
"lunasea.Descending": "Descendente",
"lunasea.Develop": "Desenvolver",
"lunasea.Disable": "Desativar",
"lunasea.Disabled": "Desativado",
"lunasea.Dismiss": "Dispensar",
"lunasea.Edge": "Edge",
"lunasea.Error": "Erro",
"lunasea.ExternalModules": "Módulos Externos",
"lunasea.FullChangelog": "Registro de alterações completo",
"lunasea.GoBack": "Voltar",
"lunasea.GoToSettings": "Ir para as Definições",
"lunasea.GridView": "Visualização em Grade",
"lunasea.Home": "Home",
"lunasea.Hours": "{} Horas",
"lunasea.HoursAgo": "{} Horas atrás",
"lunasea.IncorrectEncryptionKey": "Chave de encriptação incorreta",
"lunasea.Internal": "Interno",
"lunasea.InvalidFileTypeSelected": "Tipo de arquivo selecionado inválido",
"lunasea.JustNow": "Agora mesmo",
"lunasea.Minutes": "{} Minutos",
"lunasea.MinutesAgo": "{} Minutos atrás",
"lunasea.Module": "Módulo",
"lunasea.ModuleIsNotEnabled": "{} Não Está Ativo",
"lunasea.Months": "{} Meses",
"lunasea.MonthsAgo": "{} Meses atrás",
"lunasea.New": "Novo",
"lunasea.NoModulesEnabled": "Nenhum Módulo Ativado",
"lunasea.NotSet": "Não Definido",
"lunasea.OneDay": "1 Dia",
"lunasea.OneDayAgo": "1 Dia atrás",
"lunasea.OneHour": "1 Hora",
"lunasea.OneHourAgo": "1 Hora atrás",
"lunasea.OneMinute": "1 Minuto",
"lunasea.OneMinuteAgo": "1 Minuto atrás",
"lunasea.OneMonth": "1 Mês",
"lunasea.OneMonthAgo": "1 Mês atrás",
"lunasea.OneSecond": "1 Segundo",
"lunasea.OneSecondAgo": "1 Segundo atrás",
"lunasea.OneYear": "1 Ano",
"lunasea.OneYearAgo": "1 Ano atrás",
"lunasea.Options": "Opções",
"lunasea.Page": "Página",
"lunasea.PlatformSpecific": "Específico da plataforma",
"lunasea.PleaseTryAgain": "Por favor, tente novamente",
"lunasea.Production": "Produção",
"lunasea.Refresh": "Atualizar",
"lunasea.Refreshing": "Atualizando…",
"lunasea.Remove": "Remover",
"lunasea.Rename": "Renomear",
"lunasea.Restore": "Restaurar",
"lunasea.Retry": "Repetir",
"lunasea.ReturnToDashboard": "Voltar ao painel de aplicações",
"lunasea.SearchTextBar": "Procurar…",
"lunasea.Seconds": "{} Segundos",
"lunasea.SecondsAgo": "{} Segundos atrás",
"lunasea.Set": "Definir",
"lunasea.Settings": "Definições",
"lunasea.Stable": "Estável",
"lunasea.Today": "Hoje",
"lunasea.TransactionFailure": "Falha na transação",
"lunasea.TryAgain": "Tente novamente",
"lunasea.Tweaks": "Ajustes",
"lunasea.UnderAMinute": "Em menos de um minuto",
"lunasea.Unknown": "Desconhecido",
"lunasea.UnknownDate": "Data Desconhecida",
"lunasea.UnknownError": "Erro Desconhecido",
"lunasea.UnknownModule": "Módulo Desconhecido",
"lunasea.Update": "Atualizar",
"lunasea.View": "Visão",
"lunasea.Warning": "Aviso",
"lunasea.Website": "Website",
"lunasea.Years": "{} Anos",
"lunasea.YearsAgo": "{} Anos atrás",
"overseerr.NoRequestsFound": "Nenhum Pedido Encontrado",
"overseerr.Requests": "Pedidos",
"overseerr.NoUsersFound": "Nenhum Usuário Encontrado",
@@ -67,18 +126,80 @@
"overseerr.UnknownUser": "Usuário Desconhecido",
"overseerr.Users": "Usuários",
"radarr.AddMovie": "Adicionar Filme",
"radarr.AddMovieAndSearch": "Adicionar + Pesquisar",
"radarr.AddedTag": "Etiqueta adicionada",
"radarr.Age": "Idade",
"radarr.All": "Todos",
"radarr.Alphabetical": "Alfabética",
"radarr.Approved": "Aprovado",
"radarr.Audio": "Áudio",
"radarr.Automatic": "Automático",
"radarr.AvailabilityUnknown": "Disponibilidade Desconhecida",
"radarr.AvailableIn": "Disponível em {}",
"radarr.AvailableToday": "Disponível Hoje",
"radarr.BackupDatabase": "Backup do Banco de dados",
"radarr.Channels": "Canais",
"radarr.CinemaDateUnknown": "Data nos Cinemas Desconhecida",
"radarr.Codec": "Codec",
"radarr.Configure": "Configurar",
"radarr.Copy": "Copiar",
"radarr.CopyFull": "Cópia Física/Copiar Arquivos",
"radarr.Discover": "Descobrir",
"radarr.Disks": "Discos",
"radarr.DownloadFailed": "Download falhou",
"radarr.DownloadIgnored": "Download ignorado",
"radarr.EditMovie": "Editar Filme",
"radarr.FPS": "FPS",
"radarr.FailedToAddTag": "Falha ao adicionar etiqueta",
"radarr.FilterCatalogue": "Filtrar Catálogo",
"radarr.GrabbedFrom": "Obtido de {}",
"radarr.History": "Histórico",
"radarr.HistoryDescription": "Ver atividade recente",
"radarr.Import": "Importar",
"radarr.ImportMode": "Modo de importação",
"radarr.InCinemas": "No cinema",
"radarr.InCinemasIn": "No cinema em {}",
"radarr.InCinemasToday": "Hoje no cinema",
"radarr.Interactive": "Interativo",
"radarr.Language": "Idioma",
"radarr.Languages": "Idiomas",
"radarr.ManualImport": "Importação manual",
"radarr.ManualImportDescription": "Importar filmes do sistema de arquivos",
"radarr.MinimumAvailability": "Disponibilidade mínima",
"radarr.More": "Mais",
"radarr.Movie": "Filme",
"radarr.MovieFileDeleted": "Arquivo do filme excluído",
"radarr.MovieFileRenamed": "Arquivo do filme renomeado",
"radarr.MovieImported": "Filme importado ({})",
"radarr.MovieNotFound": "Filme não encontrado",
"radarr.MoviePath": "Caminho do filme",
"radarr.Movies": "Filmes",
"radarr.NoDisksFound": "Nenhum disco encontrado",
"radarr.NoFilesFound": "Nenhum arquivo encontrado",
"radarr.NoHistoryFound": "Nenhum histórico encontrado",
"radarr.NoMoviesFound": "Nenhum filme encontrado",
"radarr.NoResultsFound": "Nenhum resultado encontrado",
"radarr.NoRootFoldersFound": "Nenhuma pasta raiz encontrada",
"radarr.NoSubdirectoriesFound": "Nenhum subdiretório encontrado",
"radarr.NoSummaryIsAvailable": "Nenhum resumo está disponível.",
"radarr.NoTagsFound": "Nenhuma etiqueta encontrada",
"radarr.Other": "Outro",
"radarr.ParentDirectory": "Diretório Parental",
"radarr.PhysicalRelease": "Lançamento Físico",
"radarr.Quality": "Qualidade",
"radarr.QualityProfile": "Perfil de qualidade",
"radarr.Queue": "Fila",
"radarr.QueueDescription": "Ver conteúdo ativo e enfileirado",
"radarr.RefreshMovie": "Atualizar filme",
"radarr.Rejected": "Rejeitado",
"radarr.Released": "Lançado",
"radarr.ReleasedToday": "Lançado hoje",
"radarr.Releases": "Lançamentos",
"radarr.RemoveMovie": "Remover filme",
"radarr.Resolution": "Resolução",
"radarr.RootFolder": "Pasta raiz",
"radarr.RootFolders": "Pastas raiz",
"radarr.Runtime": "Tempo de execução",
"search.Subcategories": "Subcategorias",
"search.Size": "Tamanho",
"search.SentTo": "Enviar para {}",
@@ -376,6 +497,31 @@
"sonarr.NoEpisodesFound": "Nenhum Episódio Encontrado",
"sonarr.AddedOn": "Adicionado Em",
"sonarr.AddedSeries": "Séries Adicionadas",
"sonarr.Destination": "Destino",
"sonarr.All": "Tudo",
"sonarr.Approved": "Aprovado",
"sonarr.Automatic": "Automático",
"sonarr.BackingUpDatabase": "Fazendo backup do banco de dados{}",
"sonarr.BackingUpDatabaseDescription": "Fazendo backup do banco de dados em segundo plano",
"sonarr.Channels": "Canais",
"sonarr.Client": "Cliente",
"sonarr.Continuing": "Continuando",
"sonarr.DeleteReasonUpgrade": "O arquivo foi excluído para importar uma atualização",
"sonarr.DestinationRelative": "Destino relativo",
"sonarr.Download": "Baixar",
"sonarr.BackupDatabase": "Backup do banco de dados",
"sonarr.CheckDownloadClient": "Verifique o cliente de download para obter mais detalhes",
"sonarr.DeleteReasonMissingFromDisk": "O Sonarr não conseguiu encontrar o arquivo no disco, então ele foi removido",
"sonarr.EditSeries": "Editar séries",
"sonarr.DownloadingWithMessage": "Baixando: {}",
"sonarr.Downloading": "Baixando",
"sonarr.FailedToBackupDatabase": "Falha ao fazer backup do banco de dados",
"sonarr.DownloadClientUnavailable": "Cliente de download não está disponível",
"sonarr.Downloaded": "Baixado",
"sonarr.DownloadedImporting": "Baixado: Importando",
"sonarr.DownloadedWaitingToImport": "Baixado: Aguardando para importar",
"sonarr.DownloadedWaitingToProcess": "Baixado: Aguardando para processar",
"sonarr.EmptyQueue": "Fila vazia",
"tautulli.Terminate": "Terminar",
"tautulli.Subtitle": "Legenda",
"tautulli.Stream": "Transmissão",

View File

@@ -34,38 +34,65 @@
"lunasea.Cancel": "İptal",
"lunasea.Candidate": "Aday",
"lunasea.ChangeProfiles": "Profilleri Değiştir",
"lunasea.Changelog": "Değişiklik Günlüğü",
"lunasea.CheckLogsMessage": "Daha fazla ayrıntı için günlük kayıtlarına bakın",
"lunasea.Chores": "İşler",
"lunasea.Clear": "Temizle",
"lunasea.Close": "Kapat",
"lunasea.ComingSoon": "Yakında Gelecek",
"lunasea.Copied": "Kopyalandı",
"lunasea.CopiedContentToTheClipboard": "İçerik Panoya Kopyalandı",
"lunasea.Critical": "Kritik",
"lunasea.Dashboard": "Denetim Paneli",
"lunasea.Days": "{} Gün",
"lunasea.DaysAgo": "{} Gün Önce",
"lunasea.Debug": "Hata Ayıklama",
"lunasea.Delete": "Sil",
"lunasea.Descending": "Azalan",
"lunasea.Develop": "Geliştir",
"lunasea.Disable": "Devre Dışı Bırak",
"lunasea.Disabled": "Devre Dışı",
"lunasea.Dismiss": "Kapat",
"lunasea.Docs": "Belgeler",
"lunasea.Edge": "Kenar",
"lunasea.Error": "Hata",
"lunasea.ExternalModules": "Harici Modüller",
"lunasea.Features": "Özellikler",
"lunasea.Fixes": "Düzeltmeler",
"lunasea.FullChangelog": "Tam Değişiklik Günlüğü",
"lunasea.GoBack": "Geri Git",
"lunasea.GoToSettings": "Ayarlara Git",
"lunasea.GridView": "Izgara Görünümü",
"lunasea.Home": "Ana Ekran",
"lunasea.Hours": "{} Saat",
"lunasea.HoursAgo": "{} Saat Önce",
"lunasea.IncorrectEncryptionKey": "Yanlış şifreleme anahtarı",
"lunasea.Internal": "Dahili",
"lunasea.InvalidFileTypeSelected": "Geçersiz Dosya Türü Seçildi",
"lunasea.JustNow": "Az Önce",
"lunasea.Minutes": "{} Dakika",
"lunasea.MinutesAgo": "{} Dakika Önce",
"lunasea.Module": "Modül",
"lunasea.ModuleIsNotEnabled": "{} Etkin Değil",
"lunasea.Months": "{} Ay",
"lunasea.MonthsAgo": "{} Ay Önce",
"lunasea.New": "Yeni",
"lunasea.NoModulesEnabled": "Etkin Modül Yok",
"lunasea.NotSet": "Ayarlanmadı",
"lunasea.OneDay": "1 Gün",
"lunasea.OneDayAgo": "1 Gün Önce",
"lunasea.OneHour": "1 Saat",
"lunasea.OneHourAgo": "1 Saat Önce",
"lunasea.OneMinute": "1 Dakika",
"lunasea.OneMinuteAgo": "1 Dakika Önce",
"lunasea.OneMonth": "1 Ay",
"lunasea.OneMonthAgo": "1 Ay Önce",
"lunasea.OneSecond": "1 Saniye",
"lunasea.OneSecondAgo": "1 Saniye Önce",
"lunasea.OneYear": "1 Yıl",
"lunasea.OneYearAgo": "1 Yıl Önce",
"lunasea.Options": "Seçenekler",
"lunasea.Other": "Diğer",
"lunasea.Page": "Sayfa",
"lunasea.PlatformSpecific": "Platforma Özgü",
"lunasea.PleaseTryAgain": "Lütfen Tekrar Deneyin",
@@ -78,19 +105,27 @@
"lunasea.Retry": "Yeniden dene",
"lunasea.ReturnToDashboard": "Denetim Paneline Dön",
"lunasea.SearchTextBar": "Ara…",
"lunasea.Seconds": "{} Saniye",
"lunasea.SecondsAgo": "{} Saniye Önce",
"lunasea.Set": "Ayarla",
"lunasea.Settings": "Ayarlar",
"lunasea.Stable": "Kararlı",
"lunasea.StartingView": "Başlangıç Görünümü",
"lunasea.Today": "Bugün",
"lunasea.TransactionFailure": "İşlem Hatası",
"lunasea.TryAgain": "Tekrar Deneyin",
"lunasea.Tweaks": "İnce Ayarlar",
"lunasea.UnderAMinute": "Bir Dakikanın Altında",
"lunasea.Unknown": "Bilinmeyen",
"lunasea.UnknownDate": "Bilinmeyen Tarih",
"lunasea.UnknownError": "Bilinmeyen Hata",
"lunasea.UnknownModule": "Bilinmeyen Modül",
"lunasea.Update": "Güncelle",
"lunasea.View": "Görünüm",
"lunasea.Warning": "Uyarı",
"lunasea.Website": "Web Sitesi",
"lunasea.Years": "{} Yıl",
"lunasea.YearsAgo": "{} Yıl Önce",
"overseerr.Users": "Kullanıcılar",
"overseerr.UnknownUser": "Bilinmeyen Kullanıcı",
"overseerr.NoUsersFound": "Kullanıcı Bulunamadı",
@@ -505,6 +540,21 @@
"settings.PasswordHint1": "Parolanız özel karakterler içeriyorsa, daha iyi destek için kullanıcı adınız ve parolanızla temel bir kimlik doğrulama başlığı eklemeyi düşünün",
"settings.ProfilesBannerLine1": "Profiller, LunaSea'ye birden fazla modül örneği eklemenize izin verir. Ana gezinme çekmecesinde profiller arasında geçiş yapabilirsiniz.",
"settings.ProfilesBannerLine2": "Newznab dizin oluşturucu arama ve harici modüller etkinleştirilir ve tüm profillerde paylaşılır.",
"settings.DownloadUpdate": "Güncellemeyi İndir",
"settings.Platform": "Platform",
"settings.Build": "İnşa",
"settings.EnableInAppNotifications": "Uygulama İçi Bildirimleri Etkinleştir",
"settings.UpToDate": "Güncel",
"settings.Version": "Sürüm",
"settings.Channel": "Kanal",
"settings.AddedProfile": "Profil Eklendi",
"settings.ChangedProfile": "Profil Değiştirildi",
"settings.NoAdditionalProfilesAdded": "Başka profil eklenmedi",
"settings.ProfileToProfile": "\"{}\" ila \"{}\"",
"settings.ViewTypeLogs": "{} Günlüklerini Görüntüle",
"settings.RenamedProfile": "Profil Yeniden Adlandırıldı",
"settings.DeletedProfile": "Profil Silindi",
"settings.NoProfilesFound": "Profil Bulunamadı",
"sonarr.AddedSeries": "Eklenen Diziler",
"sonarr.Age": "Yıl",
"sonarr.All": "Her Şey",

View File

@@ -0,0 +1,6 @@
{
"lunasea.Add": "Thêm",
"lunasea.ChangeProfiles": "Thay đổi thông tin",
"lunasea.Changelog": "Bản ghi các thay đổi",
"lunasea.CopiedContentToTheClipboard": "Nội dung đã được sao chép vào Clipboard"
}

View File

@@ -34,38 +34,65 @@
"lunasea.Cancel": "取消",
"lunasea.Candidate": "候选",
"lunasea.ChangeProfiles": "更改配置文件",
"lunasea.Changelog": "变更日志",
"lunasea.CheckLogsMessage": "检查日志以获取更多详细信息",
"lunasea.Chores": "日常事务",
"lunasea.Clear": "清除",
"lunasea.Close": "关闭",
"lunasea.ComingSoon": "即将推出",
"lunasea.Copied": "已复制",
"lunasea.CopiedContentToTheClipboard": "将内容复制到剪贴板",
"lunasea.Critical": "临界",
"lunasea.Dashboard": "仪表盘",
"lunasea.Days": "{} 天",
"lunasea.DaysAgo": "{} 几天前",
"lunasea.Debug": "调试",
"lunasea.Delete": "删除",
"lunasea.Descending": "降序",
"lunasea.Develop": "开发版",
"lunasea.Disable": "禁用",
"lunasea.Disabled": "不可用",
"lunasea.Dismiss": "解散",
"lunasea.Docs": "文档",
"lunasea.Edge": "边缘",
"lunasea.Error": "错误",
"lunasea.ExternalModules": "外部模块",
"lunasea.Features": "特征",
"lunasea.Fixes": "修复",
"lunasea.FullChangelog": "完整更新日志",
"lunasea.GoBack": "返回",
"lunasea.GoToSettings": "前往设置",
"lunasea.GridView": "网格视图",
"lunasea.Home": "首页",
"lunasea.Hours": "{} 小时",
"lunasea.HoursAgo": "{} 小时前",
"lunasea.IncorrectEncryptionKey": "不正确的加密密匙",
"lunasea.Internal": "内部的",
"lunasea.InvalidFileTypeSelected": "不正确的文件类型",
"lunasea.JustNow": "刚才",
"lunasea.Minutes": "{} 分钟",
"lunasea.MinutesAgo": "{} 几分钟前",
"lunasea.Module": "模块",
"lunasea.ModuleIsNotEnabled": "{}未启用",
"lunasea.Months": "{} 个月",
"lunasea.MonthsAgo": "{} 几个月前",
"lunasea.New": "新的",
"lunasea.NoModulesEnabled": "未启用模块",
"lunasea.NotSet": "未设置",
"lunasea.OneDay": "1天",
"lunasea.OneDayAgo": "1天前",
"lunasea.OneHour": "1小时",
"lunasea.OneHourAgo": "1小时前",
"lunasea.OneMinute": "1分钟",
"lunasea.OneMinuteAgo": "1 分钟前",
"lunasea.OneMonth": "1个月",
"lunasea.OneMonthAgo": "1个月前",
"lunasea.OneSecond": "1秒",
"lunasea.OneSecondAgo": "1 秒前",
"lunasea.OneYear": "1年",
"lunasea.OneYearAgo": "1年前",
"lunasea.Options": "选项",
"lunasea.Other": "其它",
"lunasea.Page": "页",
"lunasea.PlatformSpecific": "平台特定",
"lunasea.PleaseTryAgain": "请重试",
@@ -78,19 +105,27 @@
"lunasea.Retry": "重试",
"lunasea.ReturnToDashboard": "返回仪表板",
"lunasea.SearchTextBar": "搜索…",
"lunasea.Seconds": "{} 秒",
"lunasea.SecondsAgo": "{} 秒前",
"lunasea.Set": "确定",
"lunasea.Settings": "设置",
"lunasea.Stable": "稳定的",
"lunasea.StartingView": "开始视图",
"lunasea.Today": "今天",
"lunasea.TransactionFailure": "交易失败",
"lunasea.TryAgain": "再试一次",
"lunasea.Tweaks": "调整",
"lunasea.UnderAMinute": "不到一分钟",
"lunasea.Unknown": "未知",
"lunasea.UnknownDate": "未知日期",
"lunasea.UnknownError": "未知错误",
"lunasea.UnknownModule": "未知模块",
"lunasea.Update": "更新",
"lunasea.View": "视图",
"lunasea.Warning": "警告",
"lunasea.Website": "网站",
"lunasea.Years": "{} 年",
"lunasea.YearsAgo": "{} 年前",
"overseerr.NoRequests": "没有请求",
"overseerr.OneRequest": "1个请求",
"overseerr.SomeRequests": "{} 请求",
@@ -507,6 +542,21 @@
"settings.CurrentPassword": "当前密码",
"settings.BuildChannelsDescription": "了解其他构建渠道",
"settings.BuildChannels": "构建渠道",
"settings.Platform": "平台",
"settings.Build": "构建",
"settings.Channel": "渠道",
"settings.DownloadUpdate": "下载更新",
"settings.EnableInAppNotifications": "启用应用内通知",
"settings.UpToDate": "最新",
"settings.Version": "版本",
"settings.AddedProfile": "添加配置文件",
"settings.ChangedProfile": "更改配置文件",
"settings.DeletedProfile": "已删除的个人资料",
"settings.NoAdditionalProfilesAdded": "未添加其他配置文件",
"settings.NoProfilesFound": "未找到配置文件",
"settings.ProfileToProfile": "\"{}\" 至 \"{}\"",
"settings.RenamedProfile": "重命名配置文件",
"settings.ViewTypeLogs": "查看 {} 日志",
"sonarr.AddSeries": "添加系列",
"sonarr.AddedOn": "添加于",
"sonarr.Age": "年龄",

View File

@@ -0,0 +1 @@
{}

View File

@@ -5,14 +5,6 @@ targets:
- pubspec.*
- $package$
builders:
# Envify
envify_generator|envify:
enabled: true
generate_for:
exclude:
- lib
include:
- lib/system/environment.dart
# Hive
hive_generator:
enabled: true

View File

@@ -18,7 +18,6 @@ _Channel(s): `Stable`, `Candidate`, `Beta`, `Edge`_
The easiest way for most users with Android devices would be to download releases of LunaSea directly from the [Google Play Store](https://www.lunasea.app/playstore)!
<Tabs
groupId="channel"
defaultValue="stable"
values={[
{ label: "Stable", value: "stable" },

View File

@@ -24,7 +24,6 @@ _Channel(s): `Stable`, `Candidate`, `Beta`, `Edge`_
The easiest way for most users with iOS devices to use test channels is using the [TestFlight](https://apps.apple.com/app/testflight/id899247664) platform!
<Tabs
groupId="channel"
defaultValue="stable"
values={[
{ label: "Stable", value: "stable" },

View File

@@ -16,7 +16,6 @@ _Channel(s): `Stable`, `Candidate`, `Beta`, `Edge`_
The easiest way for most users with macOS devices would be to download releases of LunaSea using the [TestFlight](https://apps.apple.com/app/testflight/id899247664) platform!
<Tabs
groupId="channel"a
defaultValue="stable"
values={[
{ label: "Stable", value: "stable" },
@@ -54,6 +53,12 @@ _Format(s): `.dmg`, `.zip`_
All macOS releases are available in the [Build Bucket](https://builds.lunasea.app/#latest/)!
## Homebrew Cask
_Channel(s): `Stable`_<br/>
All stable releases are available via [Homebrew Cask](https://formulae.brew.sh/cask/lunasea)!
## GitHub Releases
_Channel(s): `Stable`_<br/>

View File

@@ -14,7 +14,6 @@ _Channel(s): `Stable`, `Candidate`, `Beta`, `Edge`_<br/>
All web releases of LunaSea are available on hosted instances by the LunaSea team! All communication and data stored is client-side, but there are some limitations of the platform which can be [viewed here](/getting-started/platform-restrictions).
<Tabs
groupId="channel"
defaultValue="stable"
values={[
{ label: "Stable", value: "stable" },
@@ -44,7 +43,6 @@ _Channel(s): `Stable`, `Candidate`, `Beta`, `Edge`_<br/>
All web releases of LunaSea are also available in officially hosted Docker images! There is currently only one value that needs to be configured which is the port mapping. LunaSea functions as a frontend application with all data being stored client-side.
<Tabs
groupId="channel"
defaultValue="stable"
values={[
{ label: "Stable", value: "stable" },

17
environment_config.yaml Normal file
View File

@@ -0,0 +1,17 @@
environment_config:
path: system/environment.dart
class: LunaEnvironment
fields:
build:
type: int
default: 9999999999
env_var: BUILD
commit:
type: String
default: master
env_var: COMMIT
flavor:
type: String
default: edge
env_var: FLAVOR

View File

@@ -3,7 +3,7 @@ GEM
specs:
CFPropertyList (3.0.5)
rexml
activesupport (6.1.6)
activesupport (6.1.6.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
@@ -17,20 +17,20 @@ GEM
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.587.0)
aws-sdk-core (3.130.2)
aws-partitions (1.618.0)
aws-sdk-core (3.132.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-kms (1.56.0)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.58.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.114.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.0)
aws-sigv4 (1.5.1)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.1.0)
@@ -81,13 +81,13 @@ GEM
rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.6)
dotenv (2.8.1)
emoji_regex (3.2.3)
escape (0.0.4)
ethon (0.15.0)
ffi (>= 1.15.0)
excon (0.92.3)
faraday (1.10.0)
excon (0.92.4)
faraday (1.10.1)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
@@ -106,8 +106,8 @@ GEM
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.3)
multipart-post (>= 1.2, < 3)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
@@ -116,7 +116,7 @@ GEM
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.6)
fastlane (2.205.2)
fastlane (2.209.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
@@ -159,9 +159,9 @@ GEM
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.20.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-core (0.4.2)
google-apis-androidpublisher_v3 (0.25.0)
google-apis-core (>= 0.7, < 2.a)
google-apis-core (0.7.0)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@@ -170,27 +170,27 @@ GEM
retriable (>= 2.0, < 4.a)
rexml
webrick
google-apis-iamcredentials_v1 (0.10.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-playcustomapp_v1 (0.7.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-storage_v1 (0.13.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-iamcredentials_v1 (0.13.0)
google-apis-core (>= 0.7, < 2.a)
google-apis-playcustomapp_v1 (0.10.0)
google-apis-core (>= 0.7, < 2.a)
google-apis-storage_v1 (0.17.0)
google-apis-core (>= 0.7, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.2.0)
google-cloud-storage (1.36.2)
google-cloud-storage (1.38.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.17.0)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.1.3)
googleauth (1.2.0)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
@@ -198,18 +198,18 @@ GEM
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
highline (2.0.3)
http-cookie (1.0.4)
http-cookie (1.0.5)
domain_name (~> 0.5)
httpclient (2.8.3)
i18n (1.10.0)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
jmespath (1.6.1)
json (2.6.1)
jwt (2.3.0)
json (2.6.2)
jwt (2.4.1)
memoist (0.16.2)
mini_magick (4.11.0)
mini_mime (1.1.2)
minitest (5.15.0)
minitest (5.16.2)
molinillo (0.8.0)
multi_json (1.15.0)
multipart-post (2.0.0)
@@ -222,7 +222,7 @@ GEM
plist (3.6.0)
public_suffix (4.0.7)
rake (13.0.6)
representable (3.1.1)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
@@ -233,9 +233,9 @@ GEM
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
security (0.1.3)
signet (0.16.1)
signet (0.17.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.0)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.8)
@@ -251,16 +251,16 @@ GEM
tty-cursor (~> 0.7)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (2.0.4)
tzinfo (2.0.5)
concurrent-ruby (~> 1.0)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.1)
unf_ext (0.0.8.2)
unicode-display_width (1.8.0)
webrick (1.7.0)
word_wrap (1.0.0)
xcodeproj (1.21.0)
xcodeproj (1.22.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
@@ -271,14 +271,14 @@ GEM
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.1)
xcpretty (~> 0.2, >= 0.0.7)
zeitwerk (2.5.4)
zeitwerk (2.6.0)
PLATFORMS
x86_64-darwin-21
ruby
DEPENDENCIES
cocoapods
fastlane
BUNDLED WITH
2.3.10
2.3.19

View File

@@ -1,5 +1,5 @@
platform :ios, '11.0'
$FirebaseSDKVersion = '8.15.0'
$FirebaseSDKVersion = '9.3.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

View File

@@ -1,16 +1,16 @@
PODS:
- cloud_firestore (3.1.16):
- Firebase/Firestore (= 8.15.0)
- cloud_firestore (3.4.3):
- Firebase/Firestore (= 9.3.0)
- firebase_core
- Flutter
- DKImagePickerController/Core (4.3.3):
- DKImagePickerController/Core (4.3.4):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.3)
- DKImagePickerController/PhotoGallery (4.3.3):
- DKImagePickerController/ImageDataManager (4.3.4)
- DKImagePickerController/PhotoGallery (4.3.4):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.3)
- DKImagePickerController/Resource (4.3.4)
- DKPhotoGallery (0.0.17):
- DKPhotoGallery/Core (= 0.0.17)
- DKPhotoGallery/Model (= 0.0.17)
@@ -37,81 +37,94 @@ PODS:
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Firebase/Auth (8.15.0):
- Firebase/Auth (9.3.0):
- Firebase/CoreOnly
- FirebaseAuth (~> 8.15.0)
- Firebase/CoreOnly (8.15.0):
- FirebaseCore (= 8.15.0)
- Firebase/Firestore (8.15.0):
- FirebaseAuth (~> 9.3.0)
- Firebase/CoreOnly (9.3.0):
- FirebaseCore (= 9.3.0)
- Firebase/Firestore (9.3.0):
- Firebase/CoreOnly
- FirebaseFirestore (~> 8.15.0)
- Firebase/Messaging (8.15.0):
- FirebaseFirestore (~> 9.3.0)
- Firebase/Messaging (9.3.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 8.15.0)
- Firebase/Storage (8.15.0):
- FirebaseMessaging (~> 9.3.0)
- Firebase/Storage (9.3.0):
- Firebase/CoreOnly
- FirebaseStorage (~> 8.15.0)
- firebase_auth (3.3.18):
- Firebase/Auth (= 8.15.0)
- FirebaseStorage (~> 9.3.0)
- firebase_auth (3.6.2):
- Firebase/Auth (= 9.3.0)
- firebase_core
- Flutter
- firebase_core (1.17.0):
- Firebase/CoreOnly (= 8.15.0)
- firebase_core (1.20.0):
- Firebase/CoreOnly (= 9.3.0)
- Flutter
- firebase_messaging (11.4.0):
- Firebase/Messaging (= 8.15.0)
- firebase_messaging (12.0.1):
- Firebase/Messaging (= 9.3.0)
- firebase_core
- Flutter
- firebase_storage (10.2.16):
- Firebase/Storage (= 8.15.0)
- firebase_storage (10.3.4):
- Firebase/Storage (= 9.3.0)
- firebase_core
- Flutter
- FirebaseAuth (8.15.0):
- FirebaseCore (~> 8.0)
- FirebaseAppCheckInterop (9.4.0)
- FirebaseAuth (9.3.0):
- FirebaseCore (~> 9.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.7)
- GoogleUtilities/Environment (~> 7.7)
- GTMSessionFetcher/Core (~> 1.5)
- FirebaseCore (8.15.0):
- FirebaseCoreDiagnostics (~> 8.0)
- GTMSessionFetcher/Core (< 3.0, >= 1.7)
- FirebaseAuthInterop (9.4.0)
- FirebaseCore (9.3.0):
- FirebaseCoreDiagnostics (~> 9.0)
- FirebaseCoreInternal (~> 9.0)
- GoogleUtilities/Environment (~> 7.7)
- GoogleUtilities/Logger (~> 7.7)
- FirebaseCoreDiagnostics (8.15.0):
- GoogleDataTransport (~> 9.1)
- FirebaseCoreDiagnostics (9.4.0):
- GoogleDataTransport (< 10.0.0, >= 9.1.4)
- GoogleUtilities/Environment (~> 7.7)
- GoogleUtilities/Logger (~> 7.7)
- nanopb (~> 2.30908.0)
- FirebaseFirestore (8.15.0):
- FirebaseFirestore/AutodetectLeveldb (= 8.15.0)
- FirebaseFirestore/AutodetectLeveldb (8.15.0):
- nanopb (< 2.30910.0, >= 2.30908.0)
- FirebaseCoreExtension (9.4.0):
- FirebaseCore (~> 9.0)
- FirebaseCoreInternal (9.4.0):
- "GoogleUtilities/NSData+zlib (~> 7.7)"
- FirebaseFirestore (9.3.0):
- FirebaseFirestore/AutodetectLeveldb (= 9.3.0)
- FirebaseFirestore/AutodetectLeveldb (9.3.0):
- FirebaseFirestore/Base
- FirebaseFirestore/WithLeveldb
- FirebaseFirestore/Base (8.15.0)
- FirebaseFirestore/WithLeveldb (8.15.0):
- FirebaseFirestore/Base (9.3.0)
- FirebaseFirestore/WithLeveldb (9.3.0):
- FirebaseFirestore/Base
- FirebaseInstallations (8.15.0):
- FirebaseCore (~> 8.0)
- FirebaseInstallations (9.4.0):
- FirebaseCore (~> 9.0)
- GoogleUtilities/Environment (~> 7.7)
- GoogleUtilities/UserDefaults (~> 7.7)
- PromisesObjC (< 3.0, >= 1.2)
- FirebaseMessaging (8.15.0):
- FirebaseCore (~> 8.0)
- FirebaseInstallations (~> 8.0)
- GoogleDataTransport (~> 9.1)
- PromisesObjC (~> 2.1)
- FirebaseMessaging (9.3.0):
- FirebaseCore (~> 9.0)
- FirebaseInstallations (~> 9.0)
- GoogleDataTransport (< 10.0.0, >= 9.1.4)
- GoogleUtilities/AppDelegateSwizzler (~> 7.7)
- GoogleUtilities/Environment (~> 7.7)
- GoogleUtilities/Reachability (~> 7.7)
- GoogleUtilities/UserDefaults (~> 7.7)
- nanopb (~> 2.30908.0)
- FirebaseStorage (8.15.0):
- FirebaseCore (~> 8.0)
- GTMSessionFetcher/Core (~> 1.5)
- nanopb (< 2.30910.0, >= 2.30908.0)
- FirebaseStorage (9.3.0):
- FirebaseAppCheckInterop (~> 9.0)
- FirebaseAuthInterop (~> 9.0)
- FirebaseCore (~> 9.0)
- FirebaseCoreExtension (~> 9.0)
- FirebaseStorageInternal (~> 9.0)
- FirebaseStorageInternal (9.4.0):
- FirebaseCore (~> 9.0)
- GTMSessionFetcher/Core (< 3.0, >= 1.7)
- Flutter (1.0.0)
- flutter_native_splash (0.0.1):
- Flutter
- FMDB (2.7.5):
- FMDB/standard (= 2.7.5)
- FMDB/standard (2.7.5)
- GoogleDataTransport (9.1.4):
- GoogleDataTransport (9.2.0):
- GoogleUtilities/Environment (~> 7.7)
- nanopb (< 2.30910.0, >= 2.30908.0)
- PromisesObjC (< 3.0, >= 1.2)
@@ -132,24 +145,24 @@ PODS:
- GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (7.7.0):
- GoogleUtilities/Logger
- GTMSessionFetcher/Core (1.7.2)
- GTMSessionFetcher/Core (2.0.0)
- in_app_purchase_storekit (0.0.1):
- Flutter
- nanopb (2.30908.0):
- nanopb/decode (= 2.30908.0)
- nanopb/encode (= 2.30908.0)
- nanopb/decode (2.30908.0)
- nanopb/encode (2.30908.0)
- nanopb (2.30909.0):
- nanopb/decode (= 2.30909.0)
- nanopb/encode (= 2.30909.0)
- nanopb/decode (2.30909.0)
- nanopb/encode (2.30909.0)
- package_info_plus (0.4.5):
- Flutter
- path_provider_ios (0.0.1):
- Flutter
- PromisesObjC (2.1.0)
- PromisesObjC (2.1.1)
- quick_actions_ios (0.0.1):
- Flutter
- SDWebImage (5.12.5):
- SDWebImage/Core (= 5.12.5)
- SDWebImage/Core (5.12.5)
- SDWebImage (5.13.2):
- SDWebImage/Core (= 5.13.2)
- SDWebImage/Core (5.13.2)
- share_plus (0.0.1):
- Flutter
- shared_preferences_ios (0.0.1):
@@ -169,7 +182,7 @@ DEPENDENCIES:
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
- firebase_storage (from `.symlinks/plugins/firebase_storage/ios`)
- FirebaseFirestore (from `https://github.com/invertase/firestore-ios-sdk-frameworks.git`, tag `8.15.0`)
- FirebaseFirestore (from `https://github.com/invertase/firestore-ios-sdk-frameworks.git`, tag `9.3.0`)
- Flutter (from `Flutter`)
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
- in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/ios`)
@@ -186,12 +199,17 @@ SPEC REPOS:
- DKImagePickerController
- DKPhotoGallery
- Firebase
- FirebaseAppCheckInterop
- FirebaseAuth
- FirebaseAuthInterop
- FirebaseCore
- FirebaseCoreDiagnostics
- FirebaseCoreExtension
- FirebaseCoreInternal
- FirebaseInstallations
- FirebaseMessaging
- FirebaseStorage
- FirebaseStorageInternal
- FMDB
- GoogleDataTransport
- GoogleUtilities
@@ -216,7 +234,7 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/firebase_storage/ios"
FirebaseFirestore:
:git: https://github.com/invertase/firestore-ios-sdk-frameworks.git
:tag: 8.15.0
:tag: 9.3.0
Flutter:
:path: Flutter
flutter_native_splash:
@@ -241,44 +259,49 @@ EXTERNAL SOURCES:
CHECKOUT OPTIONS:
FirebaseFirestore:
:git: https://github.com/invertase/firestore-ios-sdk-frameworks.git
:tag: 8.15.0
:tag: 9.3.0
SPEC CHECKSUMS:
cloud_firestore: c85ca781dc18eed0b05c90973b4b030e6802acc4
DKImagePickerController: 72fd378f244cef3d27288e0aebf217a4467e4012
cloud_firestore: 08093e207dfb2e6c82a6b272def699e022548786
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d
firebase_auth: ace975b530600827bd901a9a18584f7cdaf6d160
firebase_core: aa1b92020533f5c23955e388c347c58fd64f8627
firebase_messaging: 8957bf304b47daf8bf12d0b111fdecc5b33e77a3
firebase_storage: 9708f24db0c21dadf7e5494f27406326c0d4ab53
FirebaseAuth: 3e73bf8abf4fbb40f8b421f361f4cc48ee57388c
FirebaseCore: 5743c5785c074a794d35f2fff7ecc254a91e08b1
FirebaseCoreDiagnostics: 92e07a649aeb66352b319d43bdd2ee3942af84cb
FirebaseFirestore: 3a0a7e1e72e4359b92d4c38de06d84e4c4900c0a
FirebaseInstallations: 40bd9054049b2eae9a2c38ef1c3dd213df3605cd
FirebaseMessaging: 5e5118a2383b3531e730d974680954c679ca0a13
FirebaseStorage: 8019af461599b2c3bc61c6a5dbdfa3d2de66a4d9
file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95
Firebase: ef75abb1cdbc746d5a38f4e26c422c807b189b8c
firebase_auth: e4bd9a01f6c45764bf3bfb0cea4d5ce3673a92a2
firebase_core: 96214f90497b808a2cf2a24517084c5f6de37b53
firebase_messaging: a2cd2c6dd7b5430bb9e4e50e9a474413ae3bce09
firebase_storage: e95ec41580e311cb30b1ed7459b9e94fb4bbe672
FirebaseAppCheckInterop: 63119cdfc94b16c3e9421513c17f597aee2ea225
FirebaseAuth: 9ebc3577fe0acf9092df21ac314024b70aebf21e
FirebaseAuthInterop: 826d3d772b554e3675ceaab8c665008277ca9d1c
FirebaseCore: c088995ece701a021a48a1348ea0174877de2a6a
FirebaseCoreDiagnostics: aaa87098082c4d4bdd1a9557b1186d18ca85ce8c
FirebaseCoreExtension: 2cf8c542b54ad3c2d4b746c22e8828b670dcd9b0
FirebaseCoreInternal: a13302b0088fbf5f38b79b6ece49c2af7d3e05d6
FirebaseFirestore: 46c6a5f8f633267208ff16e6b72d7aedc7e77c8d
FirebaseInstallations: 61db1054e688d2bdc4e2b3f744c1b086e913b742
FirebaseMessaging: 2f6e38b6133059eb796ec224104f09379298a8c3
FirebaseStorage: 1414d27e15fa04f6350ef6602accef0e951c8bca
FirebaseStorageInternal: 425c7dc7de44d9b7e07a9f8d6515bab0f1266b87
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
GoogleDataTransport: 5fffe35792f8b96ec8d6775f5eccd83c998d5a3b
GoogleDataTransport: 1c8145da7117bd68bbbed00cf304edb6a24de00f
GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1
GTMSessionFetcher: 5595ec75acf5be50814f81e9189490412bad82ba
GTMSessionFetcher: 681175626052e03fdde7952f7e9c7a9785719506
in_app_purchase_storekit: d7fcf4646136ec258e237872755da8ea6c1b6096
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
PromisesObjC: 99b6f43f9e1044bd87a95a60beff28c2c44ddb72
quick_actions_ios: 622e9076602c57f1f937f1c13e5c59c3379347e9
SDWebImage: 0905f1b7760fc8ac4198cae0036600d67478751e
PromisesObjC: ab77feca74fa2823e7af4249b8326368e61014cb
quick_actions_ios: 5ec8f5f1ae81512ac803fe10c197ebb875767a9e
SDWebImage: 72f86271a6f3139cc7e4a89220946489d4b9a866
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
PODFILE CHECKSUM: 7a22f48d9087be0dcce286c190633d1278ba71d3
PODFILE CHECKSUM: 6bb30b45f4346b63e7fe082a3e16120ec991e70f
COCOAPODS: 1.11.3

View File

@@ -9,15 +9,15 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
424B7ABEB5E8977E2C9348C9 /* Pods_ImageNotification.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DBE50693502CA51C5722409A /* Pods_ImageNotification.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
7CC186B9F7C97544AB5A3652 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E77E818ADBC103F6D1C4AFB /* Pods_Runner.framework */; };
7F20FD56C73464B5BED6C758 /* Pods_ImageNotification.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8EF3DD76EB221DAF646B779E /* Pods_ImageNotification.framework */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
9C2991242453FE3100B93AB2 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C2991232453FE3100B93AB2 /* StoreKit.framework */; };
9C7092B325E77E470056AE0B /* NotificationService.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C7092B225E77E470056AE0B /* NotificationService.m */; };
9C7092B725E77E470056AE0B /* ImageNotification.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 9C7092AF25E77E470056AE0B /* ImageNotification.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
D9CD817BDDC5956373525427 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D107AA927A3A018B623B2ED1 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -55,17 +55,18 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0CD237656FA1DBD71A65512D /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
1BCD1F1FE3F6ADC35307EFFA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
1DC3657D308C3947A9F2F611 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
156D99FA8054FCA38F50129E /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
3484A52B82F21A322E2E7E81 /* Pods-ImageNotification.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageNotification.release.xcconfig"; path = "Target Support Files/Pods-ImageNotification/Pods-ImageNotification.release.xcconfig"; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
4138476BBE83653B0BA39DBD /* Pods-ImageNotification.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageNotification.debug.xcconfig"; path = "Target Support Files/Pods-ImageNotification/Pods-ImageNotification.debug.xcconfig"; sourceTree = "<group>"; };
5E77E818ADBC103F6D1C4AFB /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
61EABA8BB570E4C4F0094EEC /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
790CC1D00BE20DFE7C2083D2 /* Pods-ImageNotification.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageNotification.release.xcconfig"; path = "Target Support Files/Pods-ImageNotification/Pods-ImageNotification.release.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
8EF3DD76EB221DAF646B779E /* Pods_ImageNotification.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ImageNotification.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9579A235AF720D29157E06D1 /* Pods-ImageNotification.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageNotification.debug.xcconfig"; path = "Target Support Files/Pods-ImageNotification/Pods-ImageNotification.debug.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -81,9 +82,8 @@
9C7092B125E77E470056AE0B /* NotificationService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NotificationService.h; sourceTree = "<group>"; };
9C7092B225E77E470056AE0B /* NotificationService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NotificationService.m; sourceTree = "<group>"; };
9C7092B425E77E470056AE0B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
B81386416199320075C0A6F7 /* Pods-ImageNotification.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageNotification.profile.xcconfig"; path = "Target Support Files/Pods-ImageNotification/Pods-ImageNotification.profile.xcconfig"; sourceTree = "<group>"; };
DBE50693502CA51C5722409A /* Pods_ImageNotification.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ImageNotification.framework; sourceTree = BUILT_PRODUCTS_DIR; };
F661F08997AF1C71DD925940 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
D107AA927A3A018B623B2ED1 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DB4A2C713D2458BE9FE5B15D /* Pods-ImageNotification.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageNotification.profile.xcconfig"; path = "Target Support Files/Pods-ImageNotification/Pods-ImageNotification.profile.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -92,7 +92,7 @@
buildActionMask = 2147483647;
files = (
9C2991242453FE3100B93AB2 /* StoreKit.framework in Frameworks */,
7CC186B9F7C97544AB5A3652 /* Pods_Runner.framework in Frameworks */,
D9CD817BDDC5956373525427 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -100,7 +100,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
424B7ABEB5E8977E2C9348C9 /* Pods_ImageNotification.framework in Frameworks */,
7F20FD56C73464B5BED6C758 /* Pods_ImageNotification.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -179,8 +179,8 @@
isa = PBXGroup;
children = (
9C2991232453FE3100B93AB2 /* StoreKit.framework */,
DBE50693502CA51C5722409A /* Pods_ImageNotification.framework */,
5E77E818ADBC103F6D1C4AFB /* Pods_Runner.framework */,
8EF3DD76EB221DAF646B779E /* Pods_ImageNotification.framework */,
D107AA927A3A018B623B2ED1 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -188,12 +188,12 @@
F5D05D221249C73674C5DB0D /* Pods */ = {
isa = PBXGroup;
children = (
4138476BBE83653B0BA39DBD /* Pods-ImageNotification.debug.xcconfig */,
790CC1D00BE20DFE7C2083D2 /* Pods-ImageNotification.release.xcconfig */,
B81386416199320075C0A6F7 /* Pods-ImageNotification.profile.xcconfig */,
1BCD1F1FE3F6ADC35307EFFA /* Pods-Runner.debug.xcconfig */,
1DC3657D308C3947A9F2F611 /* Pods-Runner.release.xcconfig */,
F661F08997AF1C71DD925940 /* Pods-Runner.profile.xcconfig */,
9579A235AF720D29157E06D1 /* Pods-ImageNotification.debug.xcconfig */,
3484A52B82F21A322E2E7E81 /* Pods-ImageNotification.release.xcconfig */,
DB4A2C713D2458BE9FE5B15D /* Pods-ImageNotification.profile.xcconfig */,
156D99FA8054FCA38F50129E /* Pods-Runner.debug.xcconfig */,
0CD237656FA1DBD71A65512D /* Pods-Runner.release.xcconfig */,
61EABA8BB570E4C4F0094EEC /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@@ -205,7 +205,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
7C0016EE04018FCDF93CC641 /* [CP] Check Pods Manifest.lock */,
2B7E33903D7DB0E3BE177E6B /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
@@ -213,8 +213,8 @@
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
9C7092B825E77E470056AE0B /* Embed App Extensions */,
913957052D339C057C94DD82 /* [CP] Embed Pods Frameworks */,
4E567F66AD2DF12CB40B820B /* [CP] Copy Pods Resources */,
A5AA6E209CBC51E3320AD528 /* [CP] Embed Pods Frameworks */,
19A85A38E2A1E9A00213AB27 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -230,7 +230,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 9C7092BC25E77E470056AE0B /* Build configuration list for PBXNativeTarget "ImageNotification" */;
buildPhases = (
D66928A8628A516248435A06 /* [CP] Check Pods Manifest.lock */,
EEA1BFFCF0E7E0AB40245BEE /* [CP] Check Pods Manifest.lock */,
9C7092AB25E77E470056AE0B /* Sources */,
9C7092AC25E77E470056AE0B /* Frameworks */,
9C7092AD25E77E470056AE0B /* Resources */,
@@ -308,21 +308,7 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
4E567F66AD2DF12CB40B820B /* [CP] Copy Pods Resources */ = {
19A85A38E2A1E9A00213AB27 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -340,7 +326,7 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
7C0016EE04018FCDF93CC641 /* [CP] Check Pods Manifest.lock */ = {
2B7E33903D7DB0E3BE177E6B /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -362,7 +348,35 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
913957052D339C057C94DD82 /* [CP] Embed Pods Frameworks */ = {
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
};
A5AA6E209CBC51E3320AD528 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -372,12 +386,17 @@
"${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework",
"${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework",
"${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseAppCheckInterop/FirebaseAppCheckInterop.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseAuth/FirebaseAuth.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseAuthInterop/FirebaseAuthInterop.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCoreExtension/FirebaseCoreExtension.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseStorage/FirebaseStorage.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseStorageInternal/FirebaseStorageInternal.framework",
"${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
"${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework",
"${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework",
@@ -401,12 +420,17 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseAppCheckInterop.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseAuth.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseAuthInterop.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreDiagnostics.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreExtension.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreInternal.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseInstallations.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseMessaging.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseStorage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseStorageInternal.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework",
@@ -430,21 +454,7 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
};
D66928A8628A516248435A06 /* [CP] Check Pods Manifest.lock */ = {
EEA1BFFCF0E7E0AB40245BEE /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (

View File

@@ -81,7 +81,7 @@ platform :ios do
connect_appstore_connect
upload_to_testflight(
changelog: "Thank you for testing pre-release builds of LunaSea! Please consider joining the Discord to give feedback to the developer.\n\nChanges can be found on GitHub or by going to settings/system and tapping on the version tile!",
changelog: File.read("./changelog.txt"),
distribute_external: true,
groups: options[:groups],
ipa: options[:ipa],

View File

@@ -1,18 +1,20 @@
export 'core/cache.dart';
export 'core/database.dart';
export 'core/dialogs.dart';
export 'core/extensions.dart';
export 'core/models.dart';
export 'core/modules.dart';
export 'core/pages.dart';
export 'core/router.dart';
export 'core/services.dart';
export 'core/state.dart';
export 'core/system.dart';
export 'core/utilities.dart';
/// This file is deprecated and should no longer be actively used.
/// All imports should happen directly and canonical export files will not be used anymore.
export 'deprecated/state/module_state.dart';
export 'deprecated/state/state.dart';
export 'deprecated/router/module_router.dart';
export 'deprecated/router/page_router.dart';
export 'deprecated/router/router.dart';
export 'types/loading_state.dart';
export 'database/box.dart';
export 'database/models/profile.dart';
export 'database/tables/lunasea.dart';
export 'system/logger.dart';
export 'utils/dialogs.dart';
export 'widgets/ui.dart';
export 'modules.dart';
export 'vendor.dart'
hide
StreamProvider,

View File

@@ -1,2 +0,0 @@
export 'cache/memory_lru.dart';
export 'cache/memory_store.dart';

View File

@@ -1,4 +0,0 @@
export 'database/alerts_database.dart';
export 'database/database.dart';
export 'database/luna_database.dart';
export 'database/module_database.dart';

View File

@@ -1,53 +0,0 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
enum AlertsDatabaseValue {
PREVIOUS_BUILD,
}
extension AlertsDatabaseValueExtension on AlertsDatabaseValue {
String get key {
return 'ALERTS_${this.name}';
}
dynamic get data {
return Database.lunasea.box.get(this.key, defaultValue: this._defaultValue);
}
void put(dynamic value) {
if (this._isTypeValid(value)) {
Database.lunasea.box.put(this.key, value);
} else {
LunaLogger().warning(
this.runtimeType.toString(),
'put',
'Invalid Database Insert (${this.key}, ${value.runtimeType})',
);
}
}
bool _isTypeValid(dynamic value) {
switch (this) {
case AlertsDatabaseValue.PREVIOUS_BUILD:
return value is String;
}
}
dynamic get _defaultValue {
switch (this) {
case AlertsDatabaseValue.PREVIOUS_BUILD:
return '0.0.0';
}
}
ValueListenableBuilder listen({
Key? key,
required Widget Function(BuildContext, dynamic, Widget?) builder,
}) {
return ValueListenableBuilder(
key: key,
valueListenable: Database.alerts.box.listenable(keys: [this.key]),
builder: builder,
);
}
}

View File

@@ -1,135 +0,0 @@
import 'package:lunasea/core.dart';
import 'package:lunasea/system/platform.dart';
class Database {
static const String _DATABASE_LEGACY_PATH = 'database';
static const String _DATABASE_PATH = 'LunaSea/database';
static late _BoxManager alerts;
static late _BoxManager<ExternalModuleHiveObject> externalModules;
static late _BoxManager<IndexerHiveObject> indexers;
static late _BoxManager<LunaLogHiveObject> logs;
static late _BoxManager lunasea;
static late _BoxManager<ProfileHiveObject> profiles;
String get _databasePath {
if (LunaPlatform.isWindows || LunaPlatform.isLinux)
return _DATABASE_PATH;
else
return _DATABASE_LEGACY_PATH;
}
Future<void> initialize() async {
await Hive.initFlutter(_databasePath);
LunaDatabase().registerAdapters();
LunaModule.values.forEach((module) => module.database?.registerAdapters());
for (_BoxInstance instance in _BoxInstance.values) await instance.init();
if (Database.profiles.box.isEmpty) bootstrap();
}
Future<void> deinitialize() async {
await Hive.close();
}
void bootstrap() {
clearAll();
for (_BoxInstance instance in _BoxInstance.values) instance.bootstrap();
}
void clearAll() {
alerts.clear();
externalModules.clear();
indexers.clear();
logs.clear();
lunasea.clear();
profiles.clear();
}
}
enum _BoxInstance {
ALERTS,
EXTERNAL_MODULES,
INDEXERS,
LOGS,
LUNASEA,
PROFILES,
}
extension _BoxInstanceExtension on _BoxInstance {
String get key {
switch (this) {
case _BoxInstance.ALERTS:
return 'alerts';
case _BoxInstance.EXTERNAL_MODULES:
return 'external_modules';
case _BoxInstance.INDEXERS:
return 'indexers';
case _BoxInstance.LOGS:
return 'logs';
case _BoxInstance.LUNASEA:
return 'lunasea';
case _BoxInstance.PROFILES:
return 'profiles';
}
}
Future<void> init() async {
switch (this) {
case _BoxInstance.ALERTS:
await Hive.openBox('alerts');
Database.alerts = _BoxManager(this);
break;
case _BoxInstance.EXTERNAL_MODULES:
await Hive.openBox<ExternalModuleHiveObject>('external_modules');
Database.externalModules = _BoxManager(this);
break;
case _BoxInstance.INDEXERS:
await Hive.openBox<IndexerHiveObject>('indexers');
Database.indexers = _BoxManager(this);
break;
case _BoxInstance.LOGS:
await Hive.openBox<LunaLogHiveObject>('logs');
Database.logs = _BoxManager(this);
break;
case _BoxInstance.LUNASEA:
await Hive.openBox('lunasea');
Database.lunasea = _BoxManager(this);
break;
case _BoxInstance.PROFILES:
await Hive.openBox<ProfileHiveObject>('profiles');
Database.profiles = _BoxManager(this);
break;
}
}
void bootstrap() {
switch (this) {
case _BoxInstance.ALERTS:
break;
case _BoxInstance.EXTERNAL_MODULES:
break;
case _BoxInstance.INDEXERS:
break;
case _BoxInstance.LOGS:
break;
case _BoxInstance.LUNASEA:
LunaDatabaseValue.ENABLED_PROFILE.put('default');
break;
case _BoxInstance.PROFILES:
Database.profiles.box.put('default', ProfileHiveObject.empty());
break;
}
}
}
class _BoxManager<E> {
final _BoxInstance _instance;
_BoxManager(this._instance);
Box<E> get box => Hive.box<E>(_instance.key);
Future<void> clear() async => box.keys.forEach((k) => box.delete(k));
Future<int> size() async => box.length;
}

View File

@@ -1,218 +0,0 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
enum LunaDatabaseValue {
DRAWER_AUTOMATIC_MANAGE,
DRAWER_MANUAL_ORDER,
ENABLED_PROFILE,
NETWORKING_TLS_VALIDATION,
THEME_AMOLED,
THEME_AMOLED_BORDER,
THEME_IMAGE_BACKGROUND_OPACITY,
QUICK_ACTIONS_LIDARR,
QUICK_ACTIONS_RADARR,
QUICK_ACTIONS_SONARR,
QUICK_ACTIONS_NZBGET,
QUICK_ACTIONS_SABNZBD,
QUICK_ACTIONS_OMBI,
QUICK_ACTIONS_OVERSEERR,
QUICK_ACTIONS_TAUTULLI,
QUICK_ACTIONS_SEARCH,
USE_24_HOUR_TIME,
DEFAULT_LAUNCH_MODULE,
ENABLE_IN_APP_NOTIFICATIONS,
}
class LunaDatabase extends LunaModuleDatabase {
@override
void registerAdapters() {
// Deprecated
Hive.registerAdapter(DeprecatedLunaBrowserAdapter());
// Active
Hive.registerAdapter(ExternalModuleHiveObjectAdapter());
Hive.registerAdapter(IndexerHiveObjectAdapter());
Hive.registerAdapter(ProfileHiveObjectAdapter());
Hive.registerAdapter(LunaLogHiveObjectAdapter());
Hive.registerAdapter(LunaIndexerIconAdapter());
Hive.registerAdapter(LunaLogTypeAdapter());
Hive.registerAdapter(LunaModuleAdapter());
Hive.registerAdapter(LunaListViewOptionAdapter());
}
@override
Map<String, dynamic> export() {
Map<String, dynamic> data = {};
for (LunaDatabaseValue value in LunaDatabaseValue.values) {
switch (value) {
// Non-primitive values
case LunaDatabaseValue.DEFAULT_LAUNCH_MODULE:
data[value.key] =
(LunaDatabaseValue.DEFAULT_LAUNCH_MODULE.data as LunaModule).key;
break;
case LunaDatabaseValue.DRAWER_MANUAL_ORDER:
data[value.key] = LunaDrawer.moduleOrderedList()
.map<String>((module) => module.key)
.toList();
break;
// Primitive values
default:
data[value.key] = value.data;
break;
}
}
return data;
}
@override
void import(Map<String, dynamic> config) {
for (String key in config.keys) {
LunaDatabaseValue? value = valueFromKey(key);
if (value != null)
switch (value) {
// Non-primitive values
case LunaDatabaseValue.DEFAULT_LAUNCH_MODULE:
value.put(LunaModule.DASHBOARD.fromKey(config[key]));
break;
case LunaDatabaseValue.DRAWER_MANUAL_ORDER:
value.put(
(config[key] as List?)
?.map((item) => LunaModule.DASHBOARD.fromKey(item))
.toList(),
);
break;
// Primitive values
default:
value.put(config[key]);
break;
}
}
}
@override
LunaDatabaseValue? valueFromKey(String key) {
for (LunaDatabaseValue value in LunaDatabaseValue.values) {
if (value.key == key) return value;
}
return null;
}
}
extension LunaDatabaseValueExtension on LunaDatabaseValue {
String get key {
if (this == LunaDatabaseValue.ENABLED_PROFILE) return 'profile';
return 'LUNASEA_${this.name}';
}
dynamic get data {
return Database.lunasea.box.get(this.key, defaultValue: this._defaultValue);
}
void put(dynamic value) {
if (this._isTypeValid(value)) {
Database.lunasea.box.put(this.key, value);
} else {
LunaLogger().warning(
this.runtimeType.toString(),
'put',
'Invalid Database Insert (${this.key}, ${value.runtimeType})',
);
}
}
ValueListenableBuilder listen({
Key? key,
required Widget Function(BuildContext, dynamic, Widget?) builder,
}) {
return ValueListenableBuilder(
key: key,
valueListenable: Database.lunasea.box.listenable(keys: [this.key]),
builder: builder,
);
}
bool _isTypeValid(dynamic value) {
switch (this) {
case LunaDatabaseValue.ENABLED_PROFILE:
return value is String;
case LunaDatabaseValue.DRAWER_AUTOMATIC_MANAGE:
return value is bool;
case LunaDatabaseValue.DRAWER_MANUAL_ORDER:
return value is List;
case LunaDatabaseValue.THEME_AMOLED:
return value is bool;
case LunaDatabaseValue.THEME_AMOLED_BORDER:
return value is bool;
case LunaDatabaseValue.THEME_IMAGE_BACKGROUND_OPACITY:
return value is int;
case LunaDatabaseValue.QUICK_ACTIONS_LIDARR:
return value is bool;
case LunaDatabaseValue.QUICK_ACTIONS_RADARR:
return value is bool;
case LunaDatabaseValue.QUICK_ACTIONS_SONARR:
return value is bool;
case LunaDatabaseValue.QUICK_ACTIONS_NZBGET:
return value is bool;
case LunaDatabaseValue.QUICK_ACTIONS_SABNZBD:
return value is bool;
case LunaDatabaseValue.QUICK_ACTIONS_OMBI:
return value is bool;
case LunaDatabaseValue.QUICK_ACTIONS_OVERSEERR:
return value is bool;
case LunaDatabaseValue.QUICK_ACTIONS_TAUTULLI:
return value is bool;
case LunaDatabaseValue.QUICK_ACTIONS_SEARCH:
return value is bool;
case LunaDatabaseValue.USE_24_HOUR_TIME:
return value is bool;
case LunaDatabaseValue.DEFAULT_LAUNCH_MODULE:
return value is LunaModule;
case LunaDatabaseValue.NETWORKING_TLS_VALIDATION:
return value is bool;
case LunaDatabaseValue.ENABLE_IN_APP_NOTIFICATIONS:
return value is bool;
}
}
dynamic get _defaultValue {
switch (this) {
case LunaDatabaseValue.ENABLED_PROFILE:
return 'default';
case LunaDatabaseValue.DRAWER_AUTOMATIC_MANAGE:
return true;
case LunaDatabaseValue.DRAWER_MANUAL_ORDER:
return null;
case LunaDatabaseValue.THEME_AMOLED:
return false;
case LunaDatabaseValue.THEME_AMOLED_BORDER:
return false;
case LunaDatabaseValue.THEME_IMAGE_BACKGROUND_OPACITY:
return 20;
case LunaDatabaseValue.QUICK_ACTIONS_LIDARR:
return false;
case LunaDatabaseValue.QUICK_ACTIONS_RADARR:
return false;
case LunaDatabaseValue.QUICK_ACTIONS_SONARR:
return false;
case LunaDatabaseValue.QUICK_ACTIONS_NZBGET:
return false;
case LunaDatabaseValue.QUICK_ACTIONS_SABNZBD:
return false;
case LunaDatabaseValue.QUICK_ACTIONS_OVERSEERR:
return false;
case LunaDatabaseValue.QUICK_ACTIONS_TAUTULLI:
return false;
case LunaDatabaseValue.QUICK_ACTIONS_OMBI:
return false;
case LunaDatabaseValue.QUICK_ACTIONS_SEARCH:
return false;
case LunaDatabaseValue.USE_24_HOUR_TIME:
return false;
case LunaDatabaseValue.DEFAULT_LAUNCH_MODULE:
return LunaModule.DASHBOARD;
case LunaDatabaseValue.NETWORKING_TLS_VALIDATION:
return false;
case LunaDatabaseValue.ENABLE_IN_APP_NOTIFICATIONS:
return true;
}
}
}

View File

@@ -1,13 +0,0 @@
abstract class LunaModuleDatabase {
/// Register all adapters necessary for this module
void registerAdapters();
/// Export the current module's database into a [Map] object
Map<String, dynamic> export();
/// Receiving a map object, import a configuration
void import(Map<String, dynamic> config);
/// Return the Database enumerator value given the key
dynamic valueFromKey(String key);
}

View File

@@ -1,8 +0,0 @@
export 'extensions/async_snapshot.dart';
export 'extensions/datetime.dart';
export 'extensions/duration.dart';
export 'extensions/iap_product_details.dart';
export 'extensions/int.dart';
export 'extensions/navigator_state.dart';
export 'extensions/page_controller.dart';
export 'extensions/scroll_controller.dart';

View File

@@ -1,7 +0,0 @@
import 'package:flutter/material.dart';
extension LunaAsyncSnapshotExtension on AsyncSnapshot {
bool get lunaIsFinishedWithData {
return this.connectionState == ConnectionState.done && this.hasData;
}
}

View File

@@ -1,79 +0,0 @@
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/string.dart';
extension DateTimeExtension on DateTime {
/// Get the floor of a date.
///
/// The floor is a new [DateTime] object with only the year, month, and day copied from the original source.
DateTime get lunaFloor => DateTime(this.year, this.month, this.day);
/// Returns a string representation of the "age" of the [DateTime] object.
///
/// Compares to [DateTime.now().toLocal()] to calculate the age.
String get lunaAge {
Duration diff = DateTime.now().toLocal().difference(this);
if (diff.inSeconds < 10) return 'Just Now';
if (diff.inDays >= 1) return '${this.lunaDaysDifference} Ago';
if (diff.inHours >= 1)
return '${diff.inHours} ${diff.inHours == 1 ? 'Hour' : 'Hours'} Ago';
if (diff.inMinutes >= 1)
return '${diff.inMinutes} ${diff.inMinutes == 1 ? 'Minute' : 'Minutes'} Ago';
return '${diff.inSeconds} ${diff.inSeconds == 1 ? 'Second' : 'Seconds'} Ago';
}
/// Returns a string representation of the difference in days/months/years.
///
/// Compares to [DateTime.now()] to calculate the difference.
String get lunaDaysDifference {
Duration diff = this.difference(DateTime.now());
int absoluteDays = diff.inDays.abs();
if (absoluteDays == 0) return 'Today';
// If greater than 2 years, show in years
if (absoluteDays >= 365 * 2) return '${(absoluteDays / 365).round()} Years';
// If greater than 3 months, show in months
if (absoluteDays >= 30 * 3) return '${(absoluteDays / 30).round()} Months';
return '$absoluteDays ${absoluteDays == 1 ? "Day" : "Days"}';
}
/// Returns just the time as a string.
///
/// 3 PM will return either 15:00 (24 hour style) or 3:00 PM depending on the configured database option.
String get lunaTime => LunaDatabaseValue.USE_24_HOUR_TIME.data
? DateFormat.Hm().format(this)
: DateFormat.jm().format(this);
/// Returns just the date as a string.
///
/// Formatted as YYYY-MM-DD
String get lunaDate =>
'${this.year.toString().padLeft(4, '0')}-${this.month.toString().padLeft(2, '0')}-${this.day.toString().padLeft(2, '0')}';
/// Returns the date as a string.
///
/// Formatted as "<month name> <day>, <year>".
String lunaDateReadable({
bool shortMonth = false,
}) {
return DateFormat(shortMonth ? 'MMM dd, y' : 'MMMM dd, y')
.format(this.toLocal());
}
/// Returns the date and time as a string.
///
/// Formatted as `<month name> <day>, <year> • <hour>:<minute>:<second>`.
///
/// Set `timeOnNewLine` to true to have the time returned on a new line instead of separated by a bullet.
String lunaDateTimeReadable({
bool timeOnNewLine = false,
bool showSeconds = true,
String sameLineDelimiter = LunaUI.TEXT_BULLET,
bool shortMonth = false,
}) {
String _format = shortMonth ? 'MMM dd, y' : 'MMMM dd, y';
_format += timeOnNewLine ? '\n' : sameLineDelimiter.pad();
_format += LunaDatabaseValue.USE_24_HOUR_TIME.data ? 'HH:mm' : 'hh:mm';
_format += showSeconds ? ':ss' : '';
_format += LunaDatabaseValue.USE_24_HOUR_TIME.data ? '' : ' a';
return DateFormat(_format).format(this.toLocal());
}
}

View File

@@ -1,33 +0,0 @@
import 'package:lunasea/core.dart';
extension DurationExtension on Duration {
/// Return a string representation of the timestamp.
/// `HH:MM:SS` or `MM:SS` if the duration is less than one hour.
String get lunaTimestamp {
return [
if (this.inHours != 0) this.inHours.toString().padLeft(2, '0'),
(this.inMinutes % 60).toString().padLeft(2, '0'),
(this.inSeconds % 60).toString().padLeft(2, '0'),
].join(':');
}
/// Returns a string representation of the timestamp as words.
///
/// Format example: 1 Day, 23 Hours, 10 Minutes
String get lunaTimestampWords {
String? days, hours, minutes;
if (this.inDays == 1) days = '1 Day';
if (this.inDays > 1) days = '${this.inDays.toString()} Days';
if (this.inHours == 1) hours = '1 Hour';
if (this.inHours > 1) hours = '${(this.inHours % 24).toString()} Hours';
if (this.inMinutes == 1) minutes = '1 Minute';
if (this.inMinutes > 1)
minutes = '${(this.inMinutes % 60).toString()} Minutes';
return [
if (days != null) days,
if (hours != null) hours,
if (minutes != null) minutes,
if (minutes == null) LunaUI.TEXT_EMDASH,
].join(' ');
}
}

View File

@@ -1,80 +0,0 @@
extension IntegerBytesExtension on int? {
static const _BIT_SIZES = ['b', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb', 'Eb'];
static const _BYTE_SIZES = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB'];
String _bytesToString({int decimals = 2, position = 0, bool bytes = true}) {
if (this == null || this! <= 0) return '${0.toStringAsFixed(decimals)} B';
int chunk = bytes ? 1024 : 1000;
double size = this!.toDouble();
while (size > chunk) {
size /= chunk;
position++;
}
return '${size.toStringAsFixed(decimals)} ${bytes ? _BYTE_SIZES[position] : _BIT_SIZES[position]}';
}
/// Given an integer of the number of bytes/bits, return a string representation.
String lunaBytesToString({int decimals = 2, bool bytes = true}) =>
_bytesToString(decimals: decimals, position: 0, bytes: bytes);
/// Given an integer of the number of kilobytes/kilobits, return a string representation.
String lunaKilobytesToString({int decimals = 2, bool bytes = true}) =>
_bytesToString(decimals: decimals, position: 1, bytes: bytes);
/// Given an integer of the number of megabytes/megabits, return a string representation.
String lunaMegabytesToString({int decimals = 2, bool bytes = true}) =>
_bytesToString(decimals: decimals, position: 2, bytes: bytes);
/// Given an integer of the number of gigabytes/gigabits, return a string representation.
String lunaGigabytesToString({int decimals = 2, bool bytes = true}) =>
_bytesToString(decimals: decimals, position: 3, bytes: bytes);
}
extension IntegerTimeExtension on int? {
static const int _MINUTE_IN_SECONDS = 60;
static const int _HOUR_IN_SECONDS = 60 * 60;
static const int _DAY_IN_SECONDS = 60 * 60 * 24;
/// Given an integer duration, converts it to a readable string. Assumes the duration is in seconds, use the `divisor` and `multipler` variables to easily modify the input.
///
/// Only contains the highest factor (2.5 Days would return 2 Days).
String lunaDuration({int divisor = 1, int multiplier = 1}) {
if (this == null) return '';
int duration = ((this! * multiplier) / divisor).floor();
int days = (duration / _DAY_IN_SECONDS).floor();
if (days > 0) return '$days ${days == 1 ? 'Day' : 'Days'}';
int hours = (duration / _HOUR_IN_SECONDS).floor();
if (hours > 0) return '$hours ${hours == 1 ? 'Hour' : 'Hours'}';
int minutes = (duration / _MINUTE_IN_SECONDS).floor();
if (minutes > 0) return '$minutes ${minutes == 1 ? 'Minute' : 'Minutes'}';
return '$duration ${duration == 1 ? 'Second' : 'Seconds'}';
}
/// Given an integer duration, converts it to a readable runtime string. Assumes the duration is in seconds, use the `divisor` and `multipler` variables to easily modify the input.
///
/// Format example: 1h 23m
String lunaRuntime({int divisor = 1, int multiplier = 1}) {
if (this == null || this == 0) return '';
double runtime = ((this! * multiplier) / divisor);
if (runtime < 60) return '${runtime.floor()}m';
return '${(runtime / 60).floor()}h ${(runtime - ((runtime / 60).floor() * 60)).floor()}m';
}
/// Given an integer duration, converts it to a readable timestamp string. Assumes the duration is in seconds, use the `divisor` and `multiplier` variables to easily modify the input.
///
/// Format example: 1:23:45 (1 hour, 23 minutes, and 45 seconds)
String lunaTimestamp({int divisor = 1, int multiplier = 1}) {
if (this == null) return '';
int duration = ((this! * multiplier) / divisor).floor();
int hours = 0, minutes = 0;
while (duration >= _HOUR_IN_SECONDS) {
duration -= _HOUR_IN_SECONDS;
hours++;
}
while (duration >= _MINUTE_IN_SECONDS) {
duration -= _MINUTE_IN_SECONDS;
minutes++;
}
return '${hours.toString().padLeft(1, '0')}:${minutes.toString().padLeft(2, '0')}:${duration.toString().padLeft(2, '0')}';
}
}

View File

@@ -1,14 +0,0 @@
import 'package:flutter/material.dart';
extension NavigatorStateExtension on NavigatorState {
/// Safely pops the route by first checking that the route *can* be popped.
/// If the route can not be popped (it is the first/lowest route in the navigator), nothing occurs.
void lunaSafetyPop() {
if (this.canPop()) this.pop();
}
/// Pops every route until the route is the first/lowest route in the navigator.
void lunaPopToFirst() {
this.popUntil((route) => route.isFirst);
}
}

View File

@@ -1,16 +0,0 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
extension ScrollControllerExtension on ScrollController {
/// Animate a [Scrollable] back to 1.00, with a predefined duration and curve.
Future<void> lunaAnimateToStart() async {
if (this.hasClients)
this.animateTo(
0.00,
duration: const Duration(
milliseconds: LunaUI.ANIMATION_SPEED_SCROLLING,
),
curve: Curves.easeInOutQuart,
);
}
}

View File

@@ -1,7 +0,0 @@
import 'package:flutter/material.dart';
import 'package:lunasea/vendor.dart';
abstract class LunaPageGoRouter {
GoRoute get route;
Future<void> go(BuildContext context);
}

View File

@@ -1,4 +0,0 @@
export 'models/configuration.dart';
export 'models/logs.dart';
export 'models/types.dart';
export 'models/webhooks.dart';

View File

@@ -1,3 +0,0 @@
export 'configuration/external_module.dart';
export 'configuration/indexer.dart';
export 'configuration/profile.dart';

View File

@@ -1,49 +0,0 @@
import 'package:lunasea/core.dart';
part 'external_module.g.dart';
/// Hive database object containing all information on an indexer
@HiveType(typeId: 26, adapterName: 'ExternalModuleHiveObjectAdapter')
class ExternalModuleHiveObject extends HiveObject {
/// Create a new [ExternalModuleHiveObject] object with all fields set to empty values('', false, 0, {}, etc.)
factory ExternalModuleHiveObject.empty() => ExternalModuleHiveObject(
displayName: '',
host: '',
);
/// Create a new [ExternalModuleHiveObject] from another [ExternalModuleHiveObject] (deep-copy).
factory ExternalModuleHiveObject.fromExternalModuleHiveObject(
ExternalModuleHiveObject indexer) =>
ExternalModuleHiveObject(
displayName: indexer.displayName,
host: indexer.host,
);
/// Create a new [ExternalModuleHiveObject] from a map where the keys map 1-to-1 except for "key", which was the old key for apiKey.
///
/// - Does _not_ do type checking, and will throw an error if the type is invalid.
/// - If the key is null, sets to the "empty" value
factory ExternalModuleHiveObject.fromMap(Map module) =>
ExternalModuleHiveObject(
displayName: module['displayName'] ?? '',
host: module['host'] ?? '',
);
ExternalModuleHiveObject({
required this.displayName,
required this.host,
});
@override
String toString() => toMap().toString();
Map<String, dynamic> toMap() => {
"displayName": displayName ?? '',
"host": host ?? '',
};
@HiveField(0)
String? displayName;
@HiveField(1)
String? host;
}

View File

@@ -1,68 +0,0 @@
import 'package:lunasea/core.dart';
part 'indexer.g.dart';
/// Hive database object containing all information on an indexer
@HiveType(typeId: 1, adapterName: 'IndexerHiveObjectAdapter')
class IndexerHiveObject extends HiveObject {
/// Create a new [IndexerHiveObject] object with all fields set to empty values('', false, 0, {}, etc.)
factory IndexerHiveObject.empty() => IndexerHiveObject(
displayName: '',
host: '',
apiKey: '',
headers: {},
icon: null,
);
/// Create a new [IndexerHiveObject] from another [IndexerHiveObject] (deep-copy).
factory IndexerHiveObject.fromIndexerHiveObject(IndexerHiveObject indexer) =>
IndexerHiveObject(
displayName: indexer.displayName,
host: indexer.host,
apiKey: indexer.apiKey,
headers: indexer.headers,
icon: indexer.icon,
);
/// Create a new [IndexerHiveObject] from a map where the keys map 1-to-1 except for "key", which was the old key for apiKey.
///
/// - Does _not_ do type checking, and will throw an error if the type is invalid.
/// - If the key is null, sets to the "empty" value
factory IndexerHiveObject.fromMap(Map indexer) => IndexerHiveObject(
displayName: indexer['displayName'] ?? '',
host: indexer['host'] ?? '',
apiKey: indexer['key'] ?? '',
headers: indexer['headers'] ?? {},
icon: LunaIndexerIcon.GENERIC.fromKey(indexer['icon'] ?? ''),
);
IndexerHiveObject({
required this.displayName,
required this.host,
required this.apiKey,
required this.headers,
required this.icon,
});
@override
String toString() => toMap().toString();
Map<String, dynamic> toMap() => {
"displayName": displayName ?? '',
"host": host ?? '',
"key": apiKey ?? '',
"headers": headers ?? {},
"icon": icon?.key ?? '',
};
@HiveField(0)
String? displayName;
@HiveField(1)
String? host;
@HiveField(2)
String? apiKey;
@HiveField(3)
Map? headers;
@HiveField(4)
LunaIndexerIcon? icon;
}

View File

@@ -1,422 +0,0 @@
import 'package:lunasea/core.dart';
part 'profile.g.dart';
/// Hive database object containing all profile fields
@HiveType(typeId: 0, adapterName: 'ProfileHiveObjectAdapter')
class ProfileHiveObject extends HiveObject {
/// Create a new [ProfileHiveObject] object with all fields set to empty values('', false, 0, {}, etc.)
factory ProfileHiveObject.empty() => ProfileHiveObject(
//Lidarr
lidarrEnabled: false,
lidarrHost: '',
lidarrKey: '',
lidarrHeaders: {},
//Radarr
radarrEnabled: false,
radarrHost: '',
radarrKey: '',
radarrHeaders: {},
//Sonarr
sonarrEnabled: false,
sonarrHost: '',
sonarrKey: '',
sonarrHeaders: {},
//SABnzbd
sabnzbdEnabled: false,
sabnzbdHost: '',
sabnzbdKey: '',
sabnzbdHeaders: {},
//NZBGet
nzbgetEnabled: false,
nzbgetHost: '',
nzbgetUser: '',
nzbgetPass: '',
nzbgetHeaders: {},
//Wake on LAN
wakeOnLANEnabled: false,
wakeOnLANBroadcastAddress: '',
wakeOnLANMACAddress: '',
//Tautulli
tautulliEnabled: false,
tautulliHost: '',
tautulliKey: '',
tautulliHeaders: {},
//Ombi
ombiEnabled: false,
ombiHost: '',
ombiKey: '',
ombiHeaders: {},
//Overseerr
overseerrEnabled: false,
overseerrHost: '',
overseerrKey: '',
overseerrHeaders: {},
);
/// Create a new [ProfileHiveObject] from another [ProfileHiveObject] (deep-copy).
factory ProfileHiveObject.fromProfileHiveObject(ProfileHiveObject profile) =>
ProfileHiveObject(
//Lidarr
lidarrEnabled: profile.lidarrEnabled,
lidarrHost: profile.lidarrHost,
lidarrKey: profile.lidarrKey,
lidarrHeaders: profile.lidarrHeaders,
//Radarr
radarrEnabled: profile.radarrEnabled,
radarrHost: profile.radarrHost,
radarrKey: profile.radarrKey,
radarrHeaders: profile.radarrHeaders,
//Sonarr
sonarrEnabled: profile.sonarrEnabled,
sonarrHost: profile.sonarrHost,
sonarrKey: profile.sonarrKey,
sonarrHeaders: profile.sonarrHeaders,
//SABnzbd
sabnzbdEnabled: profile.sabnzbdEnabled,
sabnzbdHost: profile.sabnzbdHost,
sabnzbdKey: profile.sabnzbdKey,
sabnzbdHeaders: profile.sabnzbdHeaders,
//NZBGet
nzbgetEnabled: profile.nzbgetEnabled,
nzbgetHost: profile.nzbgetHost,
nzbgetUser: profile.nzbgetUser,
nzbgetPass: profile.nzbgetPass,
nzbgetHeaders: profile.nzbgetHeaders,
//Wake On LAN
wakeOnLANEnabled: profile.wakeOnLANEnabled,
wakeOnLANBroadcastAddress: profile.wakeOnLANBroadcastAddress,
wakeOnLANMACAddress: profile.wakeOnLANMACAddress,
//Tautulli
tautulliEnabled: profile.tautulliEnabled,
tautulliHost: profile.tautulliHost,
tautulliKey: profile.tautulliKey,
tautulliHeaders: profile.tautulliHeaders,
//Ombi
ombiEnabled: profile.ombiEnabled,
ombiHost: profile.ombiHost,
ombiKey: profile.ombiKey,
ombiHeaders: profile.ombiHeaders,
//Overseerr
overseerrEnabled: profile.overseerrEnabled,
overseerrHost: profile.overseerrHost,
overseerrKey: profile.overseerrKey,
overseerrHeaders: profile.overseerrHeaders,
);
/// Create a new [ProfileHiveObject] from a map where the keys map 1-to-1.
///
/// - Does _not_ do type checking, and will throw an error if the type is invalid.
/// - If the key is null, sets to the "empty" value
factory ProfileHiveObject.fromMap(Map profile) => ProfileHiveObject(
//Sonarr
sonarrEnabled: profile['sonarrEnabled'] ?? false,
sonarrHost: profile['sonarrHost'] ?? '',
sonarrKey: profile['sonarrKey'] ?? '',
sonarrHeaders: profile['sonarrHeaders'] ?? {},
//Radarr
radarrEnabled: profile['radarrEnabled'] ?? false,
radarrHost: profile['radarrHost'] ?? '',
radarrKey: profile['radarrKey'] ?? '',
radarrHeaders: profile['radarrHeaders'] ?? {},
//Lidarr
lidarrEnabled: profile['lidarrEnabled'] ?? false,
lidarrHost: profile['lidarrHost'] ?? '',
lidarrKey: profile['lidarrKey'] ?? '',
lidarrHeaders: profile['lidarrHeaders'] ?? {},
//SABnzbd
sabnzbdEnabled: profile['sabnzbdEnabled'] ?? false,
sabnzbdHost: profile['sabnzbdHost'] ?? '',
sabnzbdKey: profile['sabnzbdKey'] ?? '',
sabnzbdHeaders: profile['sabnzbdHeaders'] ?? {},
//NZBGet
nzbgetEnabled: profile['nzbgetEnabled'] ?? false,
nzbgetHost: profile['nzbgetHost'] ?? '',
nzbgetUser: profile['nzbgetUser'] ?? '',
nzbgetPass: profile['nzbgetPass'] ?? '',
nzbgetHeaders: profile['nzbgetHeaders'] ?? {},
//Wake on LAN
wakeOnLANEnabled: profile['wakeOnLANEnabled'] ?? false,
wakeOnLANBroadcastAddress: profile['wakeOnLANBroadcastAddress'] ?? '',
wakeOnLANMACAddress: profile['wakeOnLANMACAddress'] ?? '',
//Tautulli
tautulliEnabled: profile['tautulliEnabled'] ?? false,
tautulliHost: profile['tautulliHost'] ?? '',
tautulliKey: profile['tautulliKey'] ?? '',
tautulliHeaders: profile['tautulliHeaders'] ?? {},
//Ombi
ombiEnabled: profile['ombiEnabled'] ?? false,
ombiHost: profile['ombiHost'] ?? '',
ombiKey: profile['ombiKey'] ?? '',
ombiHeaders: profile['ombiHeaders'] ?? {},
//Overseerr
overseerrEnabled: profile['overseerrEnabled'] ?? false,
overseerrHost: profile['overseerrHost'] ?? '',
overseerrKey: profile['overseerrKey'] ?? '',
overseerrHeaders: profile['overseerrHeaders'] ?? {},
);
ProfileHiveObject({
//Lidarr
required this.lidarrEnabled,
required this.lidarrHost,
required this.lidarrKey,
required this.lidarrHeaders,
//Radarr
required this.radarrEnabled,
required this.radarrHost,
required this.radarrKey,
required this.radarrHeaders,
//Sonarr
required this.sonarrEnabled,
required this.sonarrHost,
required this.sonarrKey,
required this.sonarrHeaders,
//SABnzbd
required this.sabnzbdEnabled,
required this.sabnzbdHost,
required this.sabnzbdKey,
required this.sabnzbdHeaders,
//NZBGet
required this.nzbgetEnabled,
required this.nzbgetHost,
required this.nzbgetUser,
required this.nzbgetPass,
required this.nzbgetHeaders,
//Wake On LAN
required this.wakeOnLANEnabled,
required this.wakeOnLANBroadcastAddress,
required this.wakeOnLANMACAddress,
//Tautulli
required this.tautulliEnabled,
required this.tautulliHost,
required this.tautulliKey,
required this.tautulliHeaders,
//Ombi
required this.ombiEnabled,
required this.ombiHost,
required this.ombiKey,
required this.ombiHeaders,
//Overseerr
required this.overseerrEnabled,
required this.overseerrHost,
required this.overseerrKey,
required this.overseerrHeaders,
});
@override
String toString() => toMap().toString();
Map<String, dynamic> toMap() => {
"key": key,
//Sonarr
"sonarrEnabled": sonarrEnabled,
"sonarrHost": sonarrHost,
"sonarrKey": sonarrKey,
"sonarrHeaders": sonarrHeaders,
//Radarr
"radarrEnabled": radarrEnabled,
"radarrHost": radarrHost,
"radarrKey": radarrKey,
"radarrHeaders": radarrHeaders,
//Lidarr
"lidarrEnabled": lidarrEnabled,
"lidarrHost": lidarrHost,
"lidarrKey": lidarrKey,
"lidarrHeaders": lidarrHeaders,
//SABnzbd
"sabnzbdEnabled": sabnzbdEnabled,
"sabnzbdHost": sabnzbdHost,
"sabnzbdKey": sabnzbdKey,
"sabnzbdHeaders": sabnzbdHeaders,
//NZBGet
"nzbgetEnabled": nzbgetEnabled,
"nzbgetHost": nzbgetHost,
"nzbgetUser": nzbgetUser,
"nzbgetPass": nzbgetPass,
"nzbgetHeaders": nzbgetHeaders,
//Wake On LAN
"wakeOnLANEnabled": wakeOnLANEnabled,
"wakeOnLANBroadcastAddress": wakeOnLANBroadcastAddress,
"wakeOnLANMACAddress": wakeOnLANMACAddress,
//Tautulli
"tautulliEnabled": tautulliEnabled,
"tautulliHost": tautulliHost,
"tautulliKey": tautulliKey,
"tautulliHeaders": tautulliHeaders,
//Ombi
"ombiEnabled": ombiEnabled,
"ombiHost": ombiHost,
"ombiKey": ombiKey,
"ombiHeaders": ombiHeaders,
//Overseerr
"overseerrEnabled": overseerrEnabled,
"overseerrHost": overseerrHost,
"overseerrKey": overseerrKey,
"overseerrHeaders": overseerrHeaders,
};
//Lidarr
@HiveField(0)
bool? lidarrEnabled;
@HiveField(1)
String? lidarrHost;
@HiveField(2)
String? lidarrKey;
@HiveField(26)
Map? lidarrHeaders;
Map<String, dynamic> getLidarr() => {
'enabled': lidarrEnabled ?? false,
'host': lidarrHost ?? '',
'key': lidarrKey ?? '',
'headers': lidarrHeaders ?? {},
};
//Radarr
@HiveField(3)
bool? radarrEnabled;
@HiveField(4)
String? radarrHost;
@HiveField(5)
String? radarrKey;
@HiveField(27)
Map? radarrHeaders;
Map<String, dynamic> getRadarr() => {
'enabled': radarrEnabled ?? false,
'host': radarrHost ?? '',
'key': radarrKey ?? '',
'headers': radarrHeaders ?? {},
};
//Sonarr
@HiveField(6)
bool? sonarrEnabled;
@HiveField(7)
String? sonarrHost;
@HiveField(8)
String? sonarrKey;
@HiveField(21)
bool? sonarrVersion3; // Deprecated
@HiveField(28)
Map? sonarrHeaders;
Map<String, dynamic> getSonarr() => {
'enabled': sonarrEnabled ?? false,
'host': sonarrHost ?? '',
'key': sonarrKey ?? '',
'headers': sonarrHeaders ?? {},
};
//SABnzbd
@HiveField(9)
bool? sabnzbdEnabled;
@HiveField(10)
String? sabnzbdHost;
@HiveField(11)
String? sabnzbdKey;
@HiveField(29)
Map? sabnzbdHeaders;
Map<String, dynamic> getSABnzbd() => {
'enabled': sabnzbdEnabled ?? false,
'host': sabnzbdHost ?? '',
'key': sabnzbdKey ?? '',
'headers': sabnzbdHeaders ?? {},
};
//NZBGet
@HiveField(12)
bool? nzbgetEnabled;
@HiveField(13)
String? nzbgetHost;
@HiveField(14)
String? nzbgetUser;
@HiveField(15)
String? nzbgetPass;
@HiveField(22)
bool? nzbgetBasicAuth; // Deprecated
@HiveField(30)
Map? nzbgetHeaders;
Map<String, dynamic> getNZBGet() => {
'enabled': nzbgetEnabled ?? false,
'host': nzbgetHost ?? '',
'user': nzbgetUser ?? '',
'pass': nzbgetPass ?? '',
'headers': nzbgetHeaders ?? {},
};
//Wake On LAN
@HiveField(23)
bool? wakeOnLANEnabled;
@HiveField(24)
String? wakeOnLANBroadcastAddress;
@HiveField(25)
String? wakeOnLANMACAddress;
Map<String, dynamic> getWakeOnLAN() => {
'enabled': wakeOnLANEnabled ?? false,
'broadcastAddress': wakeOnLANBroadcastAddress ?? '',
'MACAddress': wakeOnLANMACAddress ?? '',
};
//Tautulli
@HiveField(31)
bool? tautulliEnabled;
@HiveField(32)
String? tautulliHost;
@HiveField(33)
String? tautulliKey;
@HiveField(35)
Map? tautulliHeaders;
Map<String, dynamic> getTautulli() => {
'enabled': tautulliEnabled ?? false,
'host': tautulliHost ?? '',
'key': tautulliKey ?? '',
'headers': tautulliHeaders ?? {},
};
//Ombi
@HiveField(36)
bool? ombiEnabled;
@HiveField(37)
String? ombiHost;
@HiveField(38)
String? ombiKey;
@HiveField(39)
Map? ombiHeaders;
Map<String, dynamic> getOmbi() => {
'enabled': ombiEnabled ?? false,
'host': ombiHost ?? '',
'key': ombiKey ?? '',
'headers': ombiHeaders ?? {},
};
//Overseerr
@HiveField(40)
bool? overseerrEnabled;
@HiveField(41)
String? overseerrHost;
@HiveField(42)
String? overseerrKey;
@HiveField(43)
Map? overseerrHeaders;
Map<String, dynamic> getOverseerr() => {
'enabled': overseerrEnabled ?? false,
'host': overseerrHost ?? '',
'key': overseerrKey ?? '',
'headers': overseerrHeaders ?? {},
};
bool get anythingEnabled {
for (LunaModule module in LunaModule.DASHBOARD.allModules()) {
if (module.isEnabled) return true;
}
return false;
}
}

View File

@@ -1,2 +0,0 @@
export 'logs/log.dart';
export 'logs/log_type.dart';

View File

@@ -1,5 +0,0 @@
export 'types/browser.dart';
export 'types/indexer_icon.dart';
export 'types/links.dart';
export 'types/list_view_option.dart';
export 'types/loading_state.dart';

View File

@@ -1,17 +0,0 @@
import 'package:lunasea/core.dart';
part 'browser.g.dart';
@HiveType(typeId: 11, adapterName: 'DeprecatedLunaBrowserAdapter')
enum DeprecatedLunaBrowser {
@HiveField(0)
APPLE_SAFARI,
@HiveField(1)
BRAVE_BROWSER,
@HiveField(2)
GOOGLE_CHROME,
@HiveField(3)
MICROSOFT_EDGE,
@HiveField(4)
MOZILLA_FIREFOX,
}

View File

@@ -1,47 +0,0 @@
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/string_links.dart';
enum LunaLinks {
BUILDS,
CHANGELOG,
DISCORD,
DOCUMENTATION,
FEEDBACK_BOARD,
GITHUB,
NOTIFICATIONS_GETTING_STARTED,
REDDIT,
BUILD_CHANNELS,
WEBLATE,
WEBSITE,
}
extension LunaLinksExtension on LunaLinks {
String get url {
switch (this) {
case LunaLinks.BUILDS:
return 'https://www.lunasea.app/builds';
case LunaLinks.CHANGELOG:
return 'https://www.lunasea.app/changelog';
case LunaLinks.DISCORD:
return 'https://www.lunasea.app/discord';
case LunaLinks.DOCUMENTATION:
return 'https://www.lunasea.app/docs';
case LunaLinks.FEEDBACK_BOARD:
return 'https://www.lunasea.app/feedback';
case LunaLinks.GITHUB:
return 'https://www.lunasea.app/github';
case LunaLinks.REDDIT:
return 'https://www.lunasea.app/reddit';
case LunaLinks.BUILD_CHANNELS:
return 'https://www.lunasea.app/build-channels';
case LunaLinks.WEBLATE:
return 'https:/www.lunasea.app/translate';
case LunaLinks.WEBSITE:
return 'https://www.lunasea.app';
case LunaLinks.NOTIFICATIONS_GETTING_STARTED:
return 'https://docs.lunasea.app/lunasea/notifications';
}
}
Future<void> launch() async => this.url.openLink();
}

View File

@@ -1,14 +0,0 @@
import 'package:lunasea/core.dart';
abstract class LunaWebhooks {
/// Handle the incoming webhook for the module.
Future<void> handle(Map<dynamic, dynamic> data);
/// Given a [LunaModule] and Firebase UID, return the module's webhook endpoint for the user.
static String buildUserTokenURL(String? token, LunaModule module) =>
'https://notify.lunasea.app/v1/${module.key}/user/$token';
/// Given a [LunaModule] and Firebase device token, return the module's webhook endpoint for the device.
static String buildDeviceTokenURL(String? token, LunaModule module) =>
'https://notify.lunasea.app/v1/${module.key}/device/$token';
}

View File

@@ -1,2 +0,0 @@
export 'pages/invalid_route.dart';
export 'pages/not_enabled.dart';

View File

@@ -1,3 +0,0 @@
export 'router/module_router.dart';
export 'router/page_router.dart';
export 'router/router.dart';

View File

@@ -1 +0,0 @@
export 'services/the_movie_db.dart';

View File

@@ -1 +0,0 @@
export 'the_movie_db/api.dart';

View File

@@ -1,16 +0,0 @@
class TheMovieDB {
static const String _IMAGE_ENDPOINT_URL = 'https://image.tmdb.org/t/p/';
static const String _IMAGE_BACKDROP_SIZE = 'w300';
static const String _IMAGE_POSTER_SIZE = 'w185';
static String? getPosterURL(String? id) {
if (id != null) return '$_IMAGE_ENDPOINT_URL$_IMAGE_POSTER_SIZE$id';
return null;
}
static String? getBackdropURL(String? id) {
if (id != null) return '$_IMAGE_ENDPOINT_URL$_IMAGE_BACKDROP_SIZE$id';
return null;
}
}

View File

@@ -1,2 +0,0 @@
export 'state/module_state.dart';
export 'state/state.dart';

View File

@@ -1,3 +0,0 @@
export 'system/configuration.dart';
export 'system/in_app_purchases.dart';
export 'system/profile.dart';

View File

@@ -1,104 +0,0 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
class LunaConfiguration {
static const String _EXTERNAL_MODULES_KEY = 'external_modules';
static const String _INDEXERS_KEY = 'indexers';
static const String _LUNASEA_KEY = 'lunasea';
static const String _PROFILES_KEY = 'profiles';
/// Returns a list of all profiles converted to a map.
List<Map<String, dynamic>> _getProfiles() {
List<Map<String, dynamic>> _data = [];
for (var key in Database.profiles.box.keys)
_data.add(Database.profiles.box.get(key)!.toMap());
return _data;
}
/// Given a list of map objects, creates or updates profiles for each object.
void _setProfiles(List data) {
Box<dynamic> box = Database.profiles.box;
for (Map profile in data)
box.put(profile['key'], ProfileHiveObject.fromMap(profile));
}
/// Returns a list of all indexers converted to a map.
List<Map<String, dynamic>> _getIndexers() {
List<Map<String, dynamic>> _data = [];
for (var key in Database.indexers.box.keys)
_data.add(Database.indexers.box.get(key)!.toMap());
return _data;
}
/// Given a list of map objects, creates or updates indexers for each object.
void _setIndexers(List data) {
Box<dynamic> box = Database.indexers.box;
for (Map indexer in data) box.add(IndexerHiveObject.fromMap(indexer));
}
/// Returns a list of all external modules converted to a map.
List<Map<String, dynamic>> _getExternalModules() {
List<Map<String, dynamic>> _data = [];
for (var key in Database.externalModules.box.keys)
_data.add(Database.externalModules.box.get(key)!.toMap());
return _data;
}
/// Given a list of map objects, creates or updates external modules for each object.
void _setExternalModules(List data) {
Box<dynamic> box = Database.externalModules.box;
for (Map module in data) box.add(ExternalModuleHiveObject.fromMap(module));
}
/// Import the entire configuration from a JSON-encoded string (typically read through a `.lunasea` backup file).
///
/// - Clears all boxes
/// - Calls [_setProfiles], [_setIndexers], and [_setExternalModules].
/// - Calls `import()` on all module databases, which implement [LunaDatabase].
/// - Resets the application state
///
/// On a failed import, resets LunaSea back to the default/base state
Future<void> import(BuildContext context, String data) async {
Map config = json.decode(data);
Database().clearAll();
try {
if (config[_PROFILES_KEY] != null) _setProfiles(config[_PROFILES_KEY]);
if (config[_INDEXERS_KEY] != null) _setIndexers(config[_INDEXERS_KEY]);
if (config[_EXTERNAL_MODULES_KEY] != null)
_setExternalModules(config[_EXTERNAL_MODULES_KEY]);
if (config[_LUNASEA_KEY] != null)
LunaDatabase().import(config[_LUNASEA_KEY] ?? {});
LunaModule.values.forEach((module) {
if (config[module.key] != null)
module.database?.import(config[module.key] ?? {});
});
} catch (error, stack) {
LunaLogger().error(
'Failed to import configuration, resetting to default',
error,
stack,
);
Database().bootstrap();
}
// Reset the entire app's state
LunaState.reset(context);
}
/// Converts the entire application configuration/database into a JSON string.
///
/// - Calls `_getProfiles()` and `_getIndexers()`
/// - Calls `export()` on all module databases, which implement [LunaModuleDatabase].
String export() {
Map<String, dynamic> config = {
_EXTERNAL_MODULES_KEY: _getExternalModules(),
_INDEXERS_KEY: _getIndexers(),
_PROFILES_KEY: _getProfiles(),
_LUNASEA_KEY: LunaDatabase().export(),
};
LunaModule.values.forEach((module) {
if (module.database != null)
config[module.key] = module.database!.export();
});
return json.encode(config);
}
}

View File

@@ -1,96 +0,0 @@
import 'package:flutter/material.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/system/platform.dart';
extension ProductDetailsExtension on ProductDetails {
IconData get icon {
switch (this.id) {
case LunaInAppPurchases.DONATION_01:
return Icons.local_drink_rounded;
case LunaInAppPurchases.DONATION_03:
return Icons.local_cafe_rounded;
case LunaInAppPurchases.DONATION_05:
return Icons.local_bar_rounded;
case LunaInAppPurchases.DONATION_10:
return Icons.fastfood_rounded;
default:
return Icons.attach_money_rounded;
}
}
String get name {
switch (this.id) {
case LunaInAppPurchases.DONATION_01:
return 'lunasea.BuyMeASoda'.tr();
case LunaInAppPurchases.DONATION_03:
return 'lunasea.BuyMeACoffee'.tr();
case LunaInAppPurchases.DONATION_05:
return 'lunasea.BuyMeABeer'.tr();
case LunaInAppPurchases.DONATION_10:
return 'lunasea.BuyMeABurger'.tr();
default:
return 'lunasea.Unknown'.tr();
}
}
}
class LunaInAppPurchases {
// Donation IAP IDs
static const DONATION_01 = 'donation_01';
static const DONATION_03 = 'donation_03';
static const DONATION_05 = 'donation_05';
static const DONATION_10 = 'donation_10';
static const DONATION_IDS = [
DONATION_01,
DONATION_03,
DONATION_05,
DONATION_10
];
static InAppPurchase get connection => InAppPurchase.instance;
static StreamSubscription<List<PurchaseDetails>>? _purchaseStream;
static List<ProductDetails> donationIAPs = [];
static bool isAvailable = false;
static bool get isSupported => LunaPlatform.isMobile;
/// Callback function for [purchaseStream].
static Future<void> _purchasedCallback(
List<PurchaseDetails> purchases) async {
for (var purchase in purchases) {
/// Handle donations by always completing the purchase
if (DONATION_IDS.contains(purchase.productID)) {
if (purchase.pendingCompletePurchase)
await connection.completePurchase(purchase);
}
}
}
/// Initialize the in-app purchases connection.
///
/// - Enables pending purchase
/// - Attach [InAppPurchaseConnection.instance.purchaseUpdateStream] listener for automatically completing IAP purchases
/// - Fetch and store donation IAPs
Future<void> initialize() async {
if (isSupported) {
isAvailable = await connection.isAvailable();
if (isAvailable) {
// Open listener
_purchaseStream = connection.purchaseStream.listen(
LunaInAppPurchases._purchasedCallback,
);
// Load donation IAPs
ProductDetailsResponse donation =
await connection.queryProductDetails(Set.from(DONATION_IDS));
donationIAPs = donation.productDetails;
donationIAPs.sort((a, b) => a.id.compareTo(b.id));
}
}
}
/// Deinitialize the in-app purchases connection.
///
/// - Cleanly cancel/close the [InAppPurchaseConnection.instance.purchaseUpdateStream] listener.
Future<void>? deinitialize() async => _purchaseStream?.cancel();
}

View File

@@ -1,125 +0,0 @@
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/settings.dart';
class LunaProfile {
/// Returns a list of the profiles, sorted by their lowercase key/display name.
List<String> profilesList() => Database.profiles.box.keys
.map<String>((profile) => profile as String)
.toList()
..sort((a, b) => a.toLowerCase().compareTo(b.toLowerCase()));
/// Safely change profiles.
///
/// Does this safely by:
/// - Ensures that the passed in profile isn't already enabled
/// - Ensures that the profile exists
Future<bool> safelyChangeProfiles(
String profile, {
bool showSnackbar = true,
bool popToFirst = false,
}) async {
if (LunaDatabaseValue.ENABLED_PROFILE.data == profile) return true;
if (Database.profiles.box.containsKey(profile)) {
LunaDatabaseValue.ENABLED_PROFILE.put(profile);
LunaState.reset(LunaState.navigatorKey.currentContext!);
if (showSnackbar)
showLunaSuccessSnackBar(
title: 'Changed Profile',
message: profile,
);
if (popToFirst) LunaState.navigatorKey.currentState!.lunaPopToFirst();
return true;
} else {
LunaLogger().warning('LunaProfile', 'changeProfile',
'Attempted to change profile to unknown profile: $profile');
return false;
}
}
/// Rename a profile.
///
/// Shows a dialog with a list of profiles, on selection:
/// - Shows a input bar for a new name
/// - Updates the profile's key (which is also the display name)
Future<bool> renameProfile({bool showSnackbar = true}) async {
List<String?> profiles = profilesList();
Tuple2<bool, String?> selectedProfile = await SettingsDialogs()
.renameProfile(LunaState.navigatorKey.currentContext!, profiles);
if (selectedProfile.item1) {
Tuple2<bool, String> newProfile = await SettingsDialogs()
.renameProfileSelected(
LunaState.navigatorKey.currentContext!, profiles);
if (newProfile.item1) {
ProfileHiveObject oldProfileObject =
Database.profiles.box.get(selectedProfile.item2)!;
Database.profiles.box.put(newProfile.item2,
ProfileHiveObject.fromProfileHiveObject(oldProfileObject));
if (LunaDatabaseValue.ENABLED_PROFILE.data == selectedProfile.item2)
LunaProfile()
.safelyChangeProfiles(newProfile.item2, showSnackbar: false);
oldProfileObject.delete();
if (showSnackbar)
showLunaSuccessSnackBar(
title: 'Renamed Profile',
message:
'"${selectedProfile.item2}" has been renamed to "${newProfile.item2}"');
}
return true;
}
return false;
}
/// Delete a profile.
///
/// Show a dialog with a list of profiles, on selection:
/// - Validate that the profile is not currently enabled
Future<bool> deleteProfile({bool showSnackbar = true}) async {
List<String?> profiles = profilesList();
profiles.remove(LunaDatabaseValue.ENABLED_PROFILE.data);
if (profiles.isNotEmpty) {
Tuple2<bool, String?> selectedProfile = await SettingsDialogs()
.deleteProfile(LunaState.navigatorKey.currentContext!, profiles);
if (selectedProfile.item1) {
if (selectedProfile.item2 != LunaDatabaseValue.ENABLED_PROFILE.data) {
Database.profiles.box.delete(selectedProfile.item2);
if (showSnackbar)
showLunaSuccessSnackBar(
title: 'Deleted Profile',
message: '"${selectedProfile.item2}" has been deleted');
return true;
}
if (showSnackbar)
showLunaErrorSnackBar(
title: 'Unable to Delete Profile',
message: 'Cannot delete the enabled profile');
}
} else {
showLunaInfoSnackBar(
title: 'No Profiles to Delete',
message: 'No additional profiles have been added');
}
return false;
}
Future<bool> addProfile({bool showSnackbar = true}) async {
List<String?> profiles = profilesList();
Tuple2<bool, String> result = await SettingsDialogs()
.addProfile(LunaState.navigatorKey.currentContext!, profiles);
if (result.item1) {
Database.profiles.box.put(result.item2, ProfileHiveObject.empty());
safelyChangeProfiles(result.item2);
if (showSnackbar)
showLunaSuccessSnackBar(
title: 'Profile Added',
message: result.item2,
);
}
return false;
}
static ProfileHiveObject get current {
LunaDatabaseValue _db = LunaDatabaseValue.ENABLED_PROFILE;
String _name = Database.lunasea.box.get(_db.key) ?? 'default';
return Database.profiles.box.get(_name) ?? ProfileHiveObject.empty();
}
}

View File

@@ -1 +0,0 @@
export 'utilities/changelog.dart';

View File

@@ -1,150 +0,0 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/string.dart';
import 'package:lunasea/system/build.dart';
import 'package:lunasea/system/flavor.dart';
class LunaChangelogSheet extends LunaBottomModalSheet {
late _Changelog _changelog;
String _version = '';
bool _isBuildDifferent() {
final db = AlertsDatabaseValue.PREVIOUS_BUILD.data;
final current = _version.split('.').map((s) => int.parse(s)).toList();
final stored = (db as String).split('.').map((s) => int.parse(s)).toList();
if (current[0] != stored[0]) return true;
if (current[1] != stored[1]) return true;
if (current[2] != stored[2]) return true;
return false;
}
@override
Future<dynamic> show({
required BuildContext context,
Widget Function(BuildContext context)? builder,
bool checkBuildVersion = false,
bool showCommitHistory = false,
}) async {
// Do not show unless it is a prod release
if (LunaFlavor.CANDIDATE.isRunningFlavor()) {
if (showCommitHistory) LunaBuild().openCommitHistory();
return;
}
try {
_changelog = await DefaultAssetBundle.of(context)
.loadString('assets/changelog.json')
.then((data) => _Changelog.fromJson(json.decode(data)));
PackageInfo _package = await PackageInfo.fromPlatform();
_version = _package.version;
if (checkBuildVersion) {
if (!_isBuildDifferent()) return;
AlertsDatabaseValue.PREVIOUS_BUILD.put(_version);
}
return this.showModal(context: context, builder: builder);
} catch (error, stack) {
LunaLogger().error('Failed to show changelog sheet', error, stack);
}
}
@override
Widget builder(BuildContext context) {
return LunaListViewModal(
children: [
LunaHeader(
text: _version,
subtitle: _changelog.motd,
),
..._buildChangeBlock(
'lunasea.New'.tr(),
_changelog.changesNew,
),
..._buildChangeBlock(
'lunasea.Tweaks'.tr(),
_changelog.changesTweaks,
),
..._buildChangeBlock(
'lunasea.Fixes'.tr(),
_changelog.changesFixes,
),
const SizedBox(height: LunaUI.DEFAULT_MARGIN_SIZE / 2),
],
actionBar: LunaBottomActionBar(
actions: [
LunaButton.text(
text: 'lunasea.FullChangelog'.tr(),
icon: Icons.track_changes_rounded,
onTap: LunaLinks.CHANGELOG.launch,
),
],
),
);
}
List<Widget> _buildChangeBlock(String header, List<_Change> changes) {
if (changes.isEmpty) return [];
return [
LunaHeader(text: header),
LunaTableCard(
content: List<LunaTableContent>.generate(
changes.length,
(index) {
String _body = changes[index]
.changes
.map((s) => '${LunaUI.TEXT_BULLET.pad()}$s')
.join('\n');
return LunaTableContent(
title: changes[index].module,
body: _body,
);
},
),
),
];
}
}
class _Changelog {
String? motd;
List<_Change> changesNew = [];
List<_Change> changesTweaks = [];
List<_Change> changesFixes = [];
static _Changelog fromJson(Map<String, dynamic> json) {
_Changelog changelog = _Changelog();
List<dynamic>? data;
changelog.motd = json['motd'] ?? 'Welcome to LunaSea!';
data = json['new'];
data?.forEach((c) => changelog.changesNew.add(_Change.fromJson(c)));
data = json['tweaks'];
data?.forEach((c) => changelog.changesTweaks.add(_Change.fromJson(c)));
data = json['fixes'];
data?.forEach((c) => changelog.changesFixes.add(_Change.fromJson(c)));
return changelog;
}
}
class _Change {
late String module;
late List<String> changes;
_Change._();
static _Change fromJson(Map<String, dynamic> json) {
_Change change = _Change._();
change.module = json['module'] as String;
change.changes = (json['changes'] as List).cast<String>();
return change;
}
}

102
lib/database/box.dart Normal file
View File

@@ -0,0 +1,102 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:lunasea/database/models/external_module.dart';
import 'package:lunasea/database/models/indexer.dart';
import 'package:lunasea/database/models/log.dart';
import 'package:lunasea/database/models/profile.dart';
import 'package:lunasea/database/table.dart';
import 'package:lunasea/system/logger.dart';
import 'package:lunasea/vendor.dart';
enum LunaBox<T> {
alerts<dynamic>('alerts'),
externalModules<LunaExternalModule>('external_modules'),
indexers<LunaIndexer>('indexers'),
logs<LunaLog>('logs'),
lunasea<dynamic>('lunasea'),
profiles<LunaProfile>('profiles');
final String key;
const LunaBox(this.key);
Box<T> get _instance => Hive.box<T>(key);
Iterable<dynamic> get keys => _instance.keys;
Iterable<T> get data => _instance.values;
int get size => _instance.length;
bool get isEmpty => _instance.isEmpty;
static Future<void> open() async {
for (final box in LunaBox.values) await box._open();
}
T? read(dynamic key, {T? fallback}) {
return _instance.get(key, defaultValue: fallback);
}
T? readAt(int index) {
return _instance.getAt(index);
}
bool contains(dynamic key) {
return _instance.containsKey(key);
}
Future<int> create(T value) async {
return _instance.add(value);
}
Future<void> update(dynamic key, T value) {
return _instance.put(key, value);
}
Future<void> delete(dynamic key) async {
return _instance.delete(key);
}
Future<void> clear() async {
_instance.keys.forEach((k) async => await _instance.delete(k));
}
Future<Box<T>> _open() async {
return Hive.openBox<T>(key);
}
ValueListenable<Box<T>> listenable([List<dynamic>? keys]) {
return _instance.listenable(keys: keys);
}
ValueListenableBuilder watch({
required Widget Function(BuildContext, Widget?) builder,
List<dynamic>? selectKeys,
List<LunaTableMixin>? selectItems,
Key? key,
Widget? child,
}) {
final items = selectItems?.map((item) => item.key).toList();
final keys = [...?selectKeys, ...?items];
return ValueListenableBuilder(
key: key,
valueListenable: listenable(keys.isNotEmpty ? keys : null),
builder: (context, _, widget) => builder(context, widget),
child: child,
);
}
}
extension LunaBoxExtension on LunaBox {
/// This only works for boxes that are typed specifically for a hive object
/// Should be improved to actually support every box.
List<Map<String, dynamic>> export() {
try {
return _instance.keys
.map<Map<String, dynamic>>((k) => _instance.get(k)!.toJson())
.toList();
} catch (error, stack) {
LunaLogger().error('Failed to export LunaBox', error, stack);
return [];
}
}
}

73
lib/database/config.dart Normal file
View File

@@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/database/database.dart';
import 'package:lunasea/database/models/external_module.dart';
import 'package:lunasea/database/models/indexer.dart';
import 'package:lunasea/database/table.dart';
class LunaConfig {
Future<void> import(BuildContext context, String data) async {
await LunaDatabase().clear();
try {
Map<String, dynamic> config = json.decode(data);
_setProfiles(config[LunaBox.profiles.key]);
_setIndexers(config[LunaBox.indexers.key]);
_setExternalModules(config[LunaBox.externalModules.key]);
for (final table in LunaTable.values) table.import(config[table.key]);
if (!LunaProfile.list.contains(LunaSeaDatabase.ENABLED_PROFILE.read())) {
LunaSeaDatabase.ENABLED_PROFILE.update(LunaProfile.list[0]);
}
} catch (error, stack) {
LunaLogger().error(
'Failed to import configuration, resetting to default',
error,
stack,
);
LunaDatabase().bootstrap(databaseCorruption: true);
}
LunaState.reset(context);
}
String export() {
Map<String, dynamic> config = {};
config[LunaBox.externalModules.key] = LunaBox.externalModules.export();
config[LunaBox.indexers.key] = LunaBox.indexers.export();
config[LunaBox.profiles.key] = LunaBox.profiles.export();
for (final table in LunaTable.values) config[table.key] = table.export();
return json.encode(config);
}
void _setProfiles(List? data) {
if (data == null) return;
for (final item in data) {
final content = (item as Map).cast<String, dynamic>();
final key = content['key'] ?? 'default';
final obj = LunaProfile.fromJson(content);
LunaBox.profiles.update(key, obj);
}
}
void _setIndexers(List? data) {
if (data == null) return;
for (final indexer in data) {
final obj = LunaIndexer.fromJson(indexer);
LunaBox.indexers.create(obj);
}
}
void _setExternalModules(List? data) {
if (data == null) return;
for (final module in data) {
final obj = LunaExternalModule.fromJson(module);
LunaBox.externalModules.create(obj);
}
}
}

View File

@@ -0,0 +1,56 @@
import 'package:lunasea/database/box.dart';
import 'package:lunasea/database/models/profile.dart';
import 'package:lunasea/database/table.dart';
import 'package:lunasea/database/tables/bios.dart';
import 'package:lunasea/database/tables/lunasea.dart';
import 'package:lunasea/system/platform.dart';
import 'package:lunasea/vendor.dart';
class LunaDatabase {
static const String _DATABASE_LEGACY_PATH = 'database';
static const String _DATABASE_PATH = 'LunaSea/database';
String get _path {
if (LunaPlatform.isWindows || LunaPlatform.isLinux) return _DATABASE_PATH;
return _DATABASE_LEGACY_PATH;
}
Future<void> initialize() async {
await Hive.initFlutter(_path);
LunaTable.register();
await open();
}
Future<void> open() async {
try {
await LunaBox.open();
if (LunaBox.profiles.isEmpty) await bootstrap();
} catch (error) {
for (final box in LunaBox.values) {
await Hive.deleteBoxFromDisk(box.key);
}
await LunaBox.open();
await bootstrap(databaseCorruption: true);
}
}
Future<void> bootstrap({
bool databaseCorruption = false,
}) async {
const defaultProfile = LunaProfile.DEFAULT_PROFILE;
await clear();
LunaBox.profiles.update(defaultProfile, LunaProfile());
LunaSeaDatabase.ENABLED_PROFILE.update(defaultProfile);
BIOSDatabase.DATABASE_CORRUPTION.update(databaseCorruption);
}
Future<void> clear() async {
for (final box in LunaBox.values) await box.clear();
}
Future<void> deinitialize() async {
await Hive.close();
}
}

View File

@@ -0,0 +1,37 @@
import 'package:lunasea/vendor.dart';
part 'deprecated.g.dart';
void registerDeprecatedAdapters() {
Hive.registerAdapter(_Deprecated02Adapter());
Hive.registerAdapter(_Deprecated03Adapter());
Hive.registerAdapter(_Deprecated04Adapter());
Hive.registerAdapter(_Deprecated05Adapter());
Hive.registerAdapter(_Deprecated06Adapter());
Hive.registerAdapter(_Deprecated07Adapter());
Hive.registerAdapter(_Deprecated11Adapter());
}
@HiveType(typeId: 2, adapterName: '_Deprecated02Adapter') // Next: 2
class _Deprecated02 extends HiveObject {}
@HiveType(typeId: 3, adapterName: '_Deprecated03Adapter') // Next: 3
class _Deprecated03 extends HiveObject {}
@HiveType(typeId: 4, adapterName: '_Deprecated04Adapter') // Next: 1
class _Deprecated04 extends HiveObject {}
@HiveType(typeId: 5, adapterName: '_Deprecated05Adapter') // Next: 3
class _Deprecated05 extends HiveObject {}
@HiveType(typeId: 6, adapterName: '_Deprecated06Adapter') // Next: 2
class _Deprecated06 extends HiveObject {}
@HiveType(typeId: 7, adapterName: '_Deprecated07Adapter') // Next: 2
class _Deprecated07 extends HiveObject {}
@HiveType(typeId: 11, adapterName: '_Deprecated11Adapter') // Next: 5
enum _Deprecated11 {
@HiveField(0)
DEPRECATED,
}

View File

@@ -0,0 +1,37 @@
import 'package:lunasea/core.dart';
part 'external_module.g.dart';
@JsonSerializable()
@HiveType(typeId: 26, adapterName: 'LunaExternalModuleAdapter')
class LunaExternalModule extends HiveObject {
@JsonKey()
@HiveField(0, defaultValue: '')
String displayName;
@JsonKey()
@HiveField(1, defaultValue: '')
String host;
LunaExternalModule({
this.displayName = '',
this.host = '',
});
@override
String toString() => json.encode(this.toJson());
Map<String, dynamic> toJson() => _$LunaExternalModuleToJson(this);
factory LunaExternalModule.fromJson(Map<String, dynamic> json) {
return _$LunaExternalModuleFromJson(json);
}
factory LunaExternalModule.clone(LunaExternalModule profile) {
return LunaExternalModule.fromJson(profile.toJson());
}
factory LunaExternalModule.get(String key) {
return LunaBox.externalModules.read(key)!;
}
}

View File

@@ -0,0 +1,53 @@
import 'package:lunasea/core.dart';
import 'package:lunasea/types/indexer_icon.dart';
part 'indexer.g.dart';
@JsonSerializable()
@HiveType(typeId: 1, adapterName: 'LunaIndexerAdapter')
class LunaIndexer extends HiveObject {
@JsonKey()
@HiveField(0, defaultValue: '')
String displayName;
@JsonKey()
@HiveField(1, defaultValue: '')
String host;
@JsonKey(name: 'key')
@HiveField(2, defaultValue: '')
String apiKey;
@JsonKey()
@HiveField(3, defaultValue: <String, String>{})
Map<String, String> headers;
@JsonKey()
@HiveField(4)
LunaIndexerIcon? icon;
LunaIndexer({
this.displayName = '',
this.host = '',
this.apiKey = '',
this.headers = const {},
this.icon,
});
@override
String toString() => json.encode(this.toJson());
Map<String, dynamic> toJson() => _$LunaIndexerToJson(this);
factory LunaIndexer.fromJson(Map<String, dynamic> json) {
return _$LunaIndexerFromJson(json);
}
factory LunaIndexer.clone(LunaIndexer profile) {
return LunaIndexer.fromJson(profile.toJson());
}
factory LunaIndexer.get(String key) {
return LunaBox.indexers.read(key)!;
}
}

View File

@@ -1,11 +1,11 @@
import 'package:lunasea/core.dart';
import 'package:lunasea/types/log_type.dart';
import 'package:stack_trace/stack_trace.dart';
part 'log.g.dart';
/// Hive database object containing all information on a log
@HiveType(typeId: 23, adapterName: 'LunaLogHiveObjectAdapter')
class LunaLogHiveObject extends HiveObject {
@HiveType(typeId: 23, adapterName: 'LunaLogAdapter')
class LunaLog extends HiveObject {
@HiveField(0)
final int timestamp;
@HiveField(1)
@@ -21,7 +21,7 @@ class LunaLogHiveObject extends HiveObject {
@HiveField(6)
final String? stackTrace;
LunaLogHiveObject({
LunaLog({
required this.timestamp,
required this.type,
this.className,
@@ -31,21 +31,21 @@ class LunaLogHiveObject extends HiveObject {
this.stackTrace,
});
factory LunaLogHiveObject.withMessage({
factory LunaLog.withMessage({
required LunaLogType type,
required String message,
String? className,
String? methodName,
}) {
int timestamp = DateTime.now().millisecondsSinceEpoch;
return LunaLogHiveObject(
return LunaLog(
timestamp: timestamp,
type: type,
message: message,
);
}
factory LunaLogHiveObject.withError({
factory LunaLog.withError({
required LunaLogType type,
required String message,
required dynamic error,
@@ -60,7 +60,7 @@ class LunaLogHiveObject extends HiveObject {
_className = trace?.frames[0].uri.toString();
_methodName = trace?.frames[0].member.toString();
}
return LunaLogHiveObject(
return LunaLog(
timestamp: timestamp,
type: type,
className: className ?? _className,
@@ -71,14 +71,14 @@ class LunaLogHiveObject extends HiveObject {
);
}
Map<String, dynamic> toMap() {
Map<String, dynamic> toJson() {
return {
"timestamp":
DateTime.fromMillisecondsSinceEpoch(timestamp).toIso8601String(),
"type": type.name,
"type": type.title,
"message": message,
if (className?.isNotEmpty ?? false) "class_name": className,
if (methodName?.isNotEmpty ?? false) "method_name": methodName,
"message": message,
if (error?.isNotEmpty ?? false) "error": error,
if (stackTrace?.isNotEmpty ?? false)
"stack_trace": stackTrace?.trim().split('\n') ?? [],

Some files were not shown because too many files have changed in this diff Show More