Merge pull request #114 from donetick/develop-rebased

Rebase Main with Develop
This commit is contained in:
Mohamad Tarbin
2026-05-30 22:10:55 -04:00
committed by GitHub
44 changed files with 2384 additions and 927 deletions

3
.gitignore vendored
View File

@@ -23,4 +23,5 @@ dist-ssr
*.sln
*.sw?
resources/android/**/*
resources/android/**/*
resources/ios/**/*

View File

@@ -0,0 +1,37 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.donetick.app",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 20,
"versionName": "1.0.20",
"outputFile": "app-release.apk"
}
],
"elementType": "File",
"baselineProfiles": [
{
"minApi": 28,
"maxApi": 30,
"baselineProfiles": [
"baselineProfiles/1/app-release.dm"
]
},
{
"minApi": 31,
"maxApi": 2147483647,
"baselineProfiles": [
"baselineProfiles/0/app-release.dm"
]
}
],
"minSdkVersionForDexing": 24
}

View File

@@ -9,7 +9,7 @@
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation"
android:name=".MainActivity"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBarLaunch"
@@ -36,6 +36,16 @@
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
</provider>
<!-- Push Notifications Icon -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@mipmap/ic_launcher" />
<!-- Push Notifications Color -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@android:color/white" />
</application>
<!-- Permissions -->
@@ -43,6 +53,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

View File

@@ -2,4 +2,36 @@ package com.donetick.app;
import com.getcapacitor.BridgeActivity;
public class MainActivity extends BridgeActivity {}
import ee.forgr.capacitor.social.login.GoogleProvider;
import ee.forgr.capacitor.social.login.SocialLoginPlugin;
import ee.forgr.capacitor.social.login.ModifiedMainActivityForSocialLoginPlugin;
import com.getcapacitor.PluginHandle;
import com.getcapacitor.Plugin;
import android.content.Intent;
import android.util.Log;
public class MainActivity extends BridgeActivity implements ModifiedMainActivityForSocialLoginPlugin {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode >= GoogleProvider.REQUEST_AUTHORIZE_GOOGLE_MIN && requestCode < GoogleProvider.REQUEST_AUTHORIZE_GOOGLE_MAX) {
PluginHandle pluginHandle = getBridge().getPlugin("SocialLogin");
if (pluginHandle == null) {
Log.i("Google Activity Result", "SocialLogin login handle is null");
return;
}
Plugin plugin = pluginHandle.getInstance();
if (!(plugin instanceof SocialLoginPlugin)) {
Log.i("Google Activity Result", "SocialLogin plugin instance is not SocialLoginPlugin");
return;
}
((SocialLoginPlugin) plugin).handleGoogleLoginIntent(requestCode, data);
}
}
@Override
public void IHaveModifiedTheMainActivityForTheUseWithSocialLoginPlugin() {}
}

View File

@@ -7,8 +7,8 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.2.1'
classpath 'com.google.gms:google-services:4.4.0'
classpath 'com.android.tools.build:gradle:8.7.2'
classpath 'com.google.gms:google-services:4.4.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View File

@@ -5,12 +5,13 @@ ext {
androidxActivityVersion = '1.9.2'
androidxAppCompatVersion = '1.7.0'
androidxCoordinatorLayoutVersion = '1.2.0'
androidxCoreVersion = '1.12.0'
androidxFragmentVersion = '1.6.2'
androidxCoreVersion = '1.15.0'
androidxFragmentVersion = '1.8.4'
coreSplashScreenVersion = '1.0.1'
androidxWebkitVersion = '1.9.0'
androidxWebkitVersion = '1.12.1'
junitVersion = '4.13.2'
androidxJunitVersion = '1.1.5'
androidxEspressoCoreVersion = '3.5.1'
androidxJunitVersion = '1.2.1'
androidxEspressoCoreVersion = '3.6.1'
cordovaAndroidVersion = '10.1.1'
firebaseMessagingVersion = '24.1.0'
}

View File

@@ -1,4 +1,4 @@
import type { CapacitorConfig } from '@capacitor/cli';
import type { CapacitorConfig } from '@capacitor/cli'
const config: CapacitorConfig = {
appId: 'com.donetick.app',
@@ -12,17 +12,17 @@ const config: CapacitorConfig = {
presentationOptions: ['badge', 'sound', 'alert'],
},
LocalNotifications: {
smallIcon: "ic_stat_icon_config_sample",
iconColor: "#488AFF",
sound: "beep.wav",
smallIcon: 'ic_stat_icon_config_sample',
iconColor: '#488AFF',
sound: 'beep.wav',
},
GoogleAuth: {
scopes: ['profile', 'email', 'openid'],
clientId: process.env.VITE_APP_GOOGLE_CLIENT_ID,
androidClientId: process.env.VITE_APP_ANDRIOD_CLIENT_ID,
iosClientId: process.env.VITE_APP_IOS_CLIENT_ID,
// GoogleAuth: {
// scopes: ['profile', 'email', 'openid'],
// clientId: process.env.VITE_APP_GOOGLE_CLIENT_ID,
// androidClientId: process.env.VITE_APP_ANDRIOD_CLIENT_ID,
// iosClientId: process.env.VITE_APP_IOS_CLIENT_ID,
// },
},
}
};
export default config;
export default config

View File

@@ -3,8 +3,13 @@
<head>
<meta charset="UTF-8" />
<!-- <link rel="icon" type="image/svg+xml" href="/logo.svg" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
/>
<title>Donetick</title>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />

View File

@@ -14,6 +14,7 @@
504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; };
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; };
50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; };
72FA9293C4A649D1BA0E5917 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 71866EB277374608AD02C137 /* PrivacyInfo.xcprivacy */; };
A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; };
D1115B492C653D60004C6043 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = D1115B482C653D60004C6043 /* GoogleService-Info.plist */; };
/* End PBXBuildFile section */
@@ -28,6 +29,7 @@
504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = "<group>"; };
71866EB277374608AD02C137 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; };
AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = "<group>"; };
D1115B482C653D60004C6043 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
@@ -62,6 +64,7 @@
504EC3051FED79650016851F /* Products */,
7F8756D8B27F46E3366F6CEA /* Pods */,
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */,
71866EB277374608AD02C137 /* PrivacyInfo.xcprivacy */,
);
sourceTree = "<group>";
};
@@ -127,8 +130,8 @@
504EC2FC1FED79650016851F /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 0920;
LastSwiftUpdateCheck = 920;
LastUpgradeCheck = 920;
TargetAttributes = {
504EC3031FED79650016851F = {
CreatedOnToolsVersion = 9.2;
@@ -169,6 +172,7 @@
504EC30D1FED79650016851F /* Main.storyboard in Resources */,
2FAD9763203C412B000D30F8 /* config.xml in Resources */,
D1115B492C653D60004C6043 /* GoogleService-Info.plist in Resources */,
72FA9293C4A649D1BA0E5917 /* PrivacyInfo.xcprivacy in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -289,7 +293,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -340,7 +344,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
@@ -358,7 +362,7 @@
CURRENT_PROJECT_VERSION = 24;
DEVELOPMENT_TEAM = 6UJJ78R3BS;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.donetick.app;
MARKETING_VERSION = 1.2.2;
@@ -378,7 +382,7 @@
CURRENT_PROJECT_VERSION = 24;
DEVELOPMENT_TEAM = 6UJJ78R3BS;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.2.2;
PRODUCT_BUNDLE_IDENTIFIER = com.donetick.app;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

@@ -1,14 +1,14 @@
{
"images" : [
"images": [
{
"filename" : "AppIcon-512@2x.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
"idiom": "universal",
"size": "1024x1024",
"filename": "AppIcon-512@2x.png",
"platform": "ios"
}
],
"info" : {
"author" : "xcode",
"version" : 1
"info": {
"author": "xcode",
"version": 1
}
}
}

View File

@@ -1,23 +1,56 @@
{
"images" : [
"images": [
{
"idiom" : "universal",
"filename" : "splash-2732x2732-2.png",
"scale" : "1x"
"idiom": "universal",
"filename": "Default@1x~universal~anyany.png",
"scale": "1x"
},
{
"idiom" : "universal",
"filename" : "splash-2732x2732-1.png",
"scale" : "2x"
"idiom": "universal",
"filename": "Default@2x~universal~anyany.png",
"scale": "2x"
},
{
"idiom" : "universal",
"filename" : "splash-2732x2732.png",
"scale" : "3x"
"idiom": "universal",
"filename": "Default@3x~universal~anyany.png",
"scale": "3x"
},
{
"appearances": [
{
"appearance": "luminosity",
"value": "dark"
}
],
"idiom": "universal",
"scale": "1x",
"filename": "Default@1x~universal~anyany-dark.png"
},
{
"appearances": [
{
"appearance": "luminosity",
"value": "dark"
}
],
"idiom": "universal",
"scale": "2x",
"filename": "Default@2x~universal~anyany-dark.png"
},
{
"appearances": [
{
"appearance": "luminosity",
"value": "dark"
}
],
"idiom": "universal",
"scale": "3x",
"filename": "Default@3x~universal~anyany-dark.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"info": {
"version": 1,
"author": "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>DoneTick</string>
<string>Donetick</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@@ -18,10 +18,27 @@
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.682262497914-5dacpk46qcc1494lood6ch8ul9c83kop</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>This app needs access to camera to take photos to attach to task or use as profile photo</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs access to photo library to select images to attach to task or use as profile photo</string>
<key>UIBackgroundModes</key>
<array/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
@@ -30,6 +47,7 @@
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
@@ -54,9 +72,5 @@
</array>
</dict>
</array>
<key>NSCameraUsageDescription</key>
<string>This app needs access to camera to take photos to attach to task or use as profile photo</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs access to photo library to select images to attach to task or use as profile photo</string>
</dict>
</plist>
</plist>

View File

@@ -130,7 +130,7 @@ PODS:
- SQLCipher/common (4.10.0)
- SQLCipher/standard (4.10.0):
- SQLCipher/common
- ZIPFoundation (0.9.19)
- ZIPFoundation (0.9.20)
DEPENDENCIES:
- "Capacitor (from `../../node_modules/@capacitor/ios`)"
@@ -248,7 +248,7 @@ SPEC CHECKSUMS:
RevenuecatPurchasesCapacitorUi: 267758d61aba42a0a3f035e6ba3c4630112357e4
RevenueCatUI: 3c72ef61b54c3f4787afab6a3b0f00cbec192063
SQLCipher: eb79c64049cb002b4e9fcb30edb7979bf4706dfc
ZIPFoundation: b8c29ea7ae353b309bc810586181fd073cb3312c
ZIPFoundation: dfd3d681c4053ff7e2f7350bc4e53b5dba3f5351
PODFILE CHECKSUM: bb6dcef70c8edc058fe3ba311f08a223fd7dbc66

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>85F4.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
</array>
<key>NSPrivacyCollectedDataTypes</key>
<array/>
</dict>
</plist>

0
ios/Podfile Normal file
View File

2203
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -30,6 +30,7 @@
"ionic:build": "npm run build",
"ionic:serve": "npm run start",
"android": "npm run build && npx cap sync android",
"cap": "npm run build && npx cap sync",
"bump": "node bump-version.js",
"bump:minor": "node bump-version.js minor",
"bump:major": "node bump-version.js major"
@@ -104,6 +105,7 @@
"@vitejs/plugin-react-swc": "^3.5.0",
"autoprefixer": "^10.4.16",
"baseline-browser-mapping": "^2.9.19",
"capacitor-set-version": "^2.2.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.2",

View File

@@ -0,0 +1,75 @@
{
"title": "Aufgaben",
"myChores": "Meine Aufgaben",
"allChores": "Alle Aufgaben",
"addChore": "Aufgabe hinzufügen",
"editChore": "Aufgabe bearbeiten",
"deleteChore": "Aufgabe löschen",
"completeChore": "Aufgabe abschließen",
"dueDate": "Fälligkeitsdatum",
"assignedTo": "Zugewiesen an",
"priority": "Priorität",
"status": "Status",
"description": "Beschreibung",
"choreView": {
"assignment": "Zuweisung",
"assigned": "Zugewiesen",
"last": "Letzte",
"schedule": "Zeitplan",
"due": "Fällig",
"statistics": "Statistiken",
"completed": "Abgeschlossen",
"times": "mal",
"details": "Details",
"createdBy": "Erstellt von",
"na": "Nicht verfügbar",
"taskCompleted": "Aufgabe abgeschlossen",
"taskCompletedMessage": "Deine Aufgabe wurde als abgeschlossen markiert",
"taskCompletionUndone": "Aufgabenabschluss wurde rückgängig gemacht.",
"taskSkipUndone": "Aufgabe überspringen wurde rückgängig gemacht.",
"undoSuccessful": "Rückgängig erfolgreich",
"undoFailed": "Rückgängig fehlgeschlagen",
"undoFailedMessage": "Die Aktion konnte nicht rückgängig gemacht werden. Bitte versuche es erneut.",
"resetTimer": "Timer zurücksetzen",
"resetTimerConfirmation": "Bist du sicher, dass du den Timer zurücksetzen möchtest? Dies löscht alle Zeitaufzeichnungen seit du die Aufgabe gestartet hast.",
"clearAllTimeRecords": "Alle Zeitaufzeichnungen löschen",
"clearAllTimeConfirmation": "Dies löscht dauerhaft alle Timer für diese Aufgabe und setzt sie zurück auf \"nicht gestartet\".",
"descriptionTitle": "Beschreibung",
"description": "Beschreibung:",
"previousNote": "Vorherige Notiz",
"previousNoteLabel": "Vorherige Notiz:",
"subtasksLabel": "Unteraufgaben:",
"taskActions": "Aufgabenaktionen",
"addNote": "Notiz hinzufügen",
"additionalNotes": "Zusätzliche Notizen:",
"notePlaceholder": "Notiz zur Fertigstellung hinzufügen...",
"setCustomCompletionTime": "Benutzerdefinierte Abschlusszeit festlegen",
"skipTask": "Aufgabe überspringen",
"skipTaskConfirmation": "Bist du sicher, dass du diese Aufgabe überspringen möchtest?",
"markComplete": "Als abgeschlossen markieren",
"markAsDone": "Als erledigt markieren",
"edit": "Bearbeiten",
"archive": "Archivieren",
"unarchive": "Archivierung aufheben",
"viewHistory": "Verlauf anzeigen",
"history": "Verlauf",
"startTimer": "Timer starten",
"start": "Starten",
"pauseTimer": "Timer pausieren",
"approve": "Genehmigen",
"reject": "Ablehnen",
"pendingApproval": "Genehmigung ausstehend",
"undo": "Rückgängig",
"skip": "Überspringen",
"cancel": "Abbrechen",
"noPriority": "Keine Priorität",
"subtasks": "Unteraufgaben",
"noDescription": "Keine Beschreibung verfügbar",
"timer": {
"active": "Timer aktiv",
"paused": "Timer pausiert",
"reset": "Timer zurücksetzen",
"delete": "Sitzung löschen"
}
}
}

View File

@@ -0,0 +1,33 @@
{
"save": "Speichern",
"cancel": "Abbrechen",
"delete": "Löschen",
"edit": "Bearbeiten",
"close": "Schließen",
"confirm": "Bestätigen",
"loading": "Laden...",
"error": "Fehler",
"success": "Erfolg",
"warning": "Warnung",
"refresh": "Aktualisieren",
"copy": "Kopieren",
"copied": "Kopiert!",
"settings": "Einstellungen",
"yes": "Ja",
"no": "Nein",
"back": "Zurück",
"backToCalendar": "Zurück zum Kalender",
"logout": "Abmelden",
"version": "Version",
"navigation": {
"allTasks": "Alle Aufgaben",
"archived": "Archiviert",
"things": "Things",
"labels": "Beschriftungen",
"projects": "Projekte",
"filters": "Filter",
"activities": "Aktivitäten",
"points": "Punkte",
"settings": "Einstellungen"
}
}

View File

@@ -0,0 +1,174 @@
{
"title": "Einstellungen",
"circleSettings": {
"title": "Kreis-Einstellungen",
"description": "Dein Account wird automatisch mit einem Kreis verbunden, wenn du einen erstellst oder beitrittst. Lade einfach Freunde ein, indem du den einzigartigen Kreis-Code oder Link unten teilst. Du erhältst eine Benachrichtigung, wenn jemand deinem Kreis beitreten möchte. Wenn du gehen möchtest, klicke einfach auf 'Kreis verlassen'.",
"circleCode": "Kreis-Code",
"copyCode": "Code kopieren",
"copyLink": "Link kopieren",
"codeCopied": "Kreis-Code kopiert!",
"linkCopied": "Kreis-Link kopiert!",
"joinCircle": "Einem Kreis beitreten",
"joinCirclePlaceholder": "Kreis-Code eingeben",
"join": "Beitreten",
"leave": "Kreis verlassen",
"leaveConfirmTitle": "Kreis verlassen",
"leaveConfirmMessage": "Bist du sicher, dass du diesen Kreis verlassen möchtest?",
"circleMembers": "Kreis-Mitglieder",
"circleMemberRequests": "Kreis-Beitrittsanfragen",
"admin": "Administrator",
"member": "Mitglied",
"pending": "Ausstehend",
"accept": "Akzeptieren",
"reject": "Ablehnen",
"makeAdmin": "Zum Administrator machen",
"makeMember": "Zum Mitglied machen",
"remove": "Entfernen",
"webhookURL": "Webhook-URL",
"webhookDescription": "Gib eine Webhook-URL ein, um Benachrichtigungen für Kreis-Ereignisse zu erhalten",
"webhookPlaceholder": "https://deine-webhook-url.com"
},
"accountSettings": {
"title": "Account-Einstellungen",
"subscription": "Abonnement",
"subscriptionStatus": "Aktueller Plan",
"free": "Kostenlos",
"plus": "Plus",
"upgrade": "Upgraden",
"cancel": "Kündigen",
"changePassword": "Passwort ändern",
"password": "Passwort",
"dangerZone": "Gefahrenbereich",
"dangerZoneDescription": "Sobald du dein Konto löschst, gibt es kein Zurück mehr. Bitte sei dir sicher.",
"deleteAccount": "Account löschen"
},
"localization": {
"title": "Sprach- und Formateinstellungen",
"description": "Passe Sprache, Datumsformat und regionale Einstellungen für dein Konto an.",
"language": "Sprache",
"languageDescription": "Wähle deine bevorzugte Sprache",
"dateFormat": "Datumsformat",
"dateFormatDescription": "Wähle, wie Daten in der gesamten Anwendung angezeigt werden sollen",
"timeFormat": "Zeitformat",
"timeFormatDescription": "Wähle 12-Stunden- oder 24-Stunden-Zeitformat",
"12hour": "12-Stunden (AM/PM)",
"24hour": "24-Stunden",
"firstDayOfWeek": "Erster Tag der Woche",
"firstDayOfWeekDescription": "Wähle, welcher Tag deine Woche beginnt",
"sunday": "Sonntag",
"monday": "Montag",
"saturday": "Samstag",
"formats": {
"mdy": "MM/TT/JJJJ (USA)",
"dmy": "TT/MM/JJJJ (Europa)",
"ymd": "JJJJ-MM-TT (ISO)",
"long": "Langes Format (z.B. 1. Januar 2024)",
"short": "Kurzes Format (z.B. 1. Jan 2024)"
}
},
"sidepanel": {
"title": "Seitenleisten-Anpassung",
"description": "Passe das Layout und die Sichtbarkeit von Karten in der Seitenleiste an. Dieser Bereich ist nur auf großen Bildschirmgeräten wie Tablets und Desktops verfügbar."
},
"theme": {
"title": "Theme-Einstellungen",
"description": "Wähle, wie die Seite für dich aussieht. Wähle ein einzelnes Theme oder synchronisiere mit deinem System und wechsle automatisch zwischen Tag- und Nacht-Themes.",
"themeMode": "Theme-Modus",
"light": "Hell",
"dark": "Dunkel",
"system": "System"
},
"notifications": {
"settingsSaved": "Einstellungen erfolgreich gespeichert",
"settingsSaveFailed": "Speichern der Einstellungen fehlgeschlagen",
"invalidWebhook": "Ungültige Webhook-URL"
},
"profile": {
"title": "Profil-Einstellungen",
"description": "Aktualisiere deinen Anzeigenamen und dein Profilbild.",
"photoUpdated": "Foto aktualisiert",
"photoUpdatedMessage": "Dein Profilbild wurde erfolgreich aktualisiert!",
"uploadFailed": "Upload fehlgeschlagen",
"uploadFailedMessage": "Das Hochladen deines Fotos ist fehlgeschlagen. Bitte versuche es erneut.",
"profileUpdated": "Profil aktualisiert",
"profileUpdatedMessage": "Deine Profilinformationen wurden erfolgreich gespeichert!",
"updateFailed": "Update fehlgeschlagen",
"updateFailedMessage": "Dein Profil konnte nicht aktualisiert werden. Bitte überprüfe deine Verbindung und versuche es erneut.",
"changePhoto": "Foto ändern",
"displayName": "Anzeigename",
"displayNamePlaceholder": "Gib deinen Anzeigenamen ein",
"timezone": "Zeitzone",
"timezonePlaceholder": "Wähle deine Zeitzone",
"save": "Speichern",
"cancel": "Abbrechen"
},
"overview": {
"title": "Einstellungen",
"subtitle": "Passe deine Erfahrung an und verwalte deine Account-Einstellungen",
"upgrade": {
"title": "Auf Plus upgraden",
"description": "Schalte mächtige Funktionen frei, um deine Produktivität zu steigern",
"button": "Jetzt upgraden",
"features": {
"richText": "Rich-Text-Beschreibungen",
"notifications": "Aufgaben-Benachrichtigungen",
"apiIntegrations": "API-Integrationen",
"advancedAutomation": "Erweiterte Automatisierung"
}
},
"sections": {
"profile": {
"title": "Profil-Einstellungen",
"description": "Aktualisiere deine Profilinformationen, Foto, Anzeigenamen und Zeitzonen-Einstellungen."
},
"circle": {
"title": "Kreis-Einstellungen",
"description": "Verwalte deinen Kreis, lade Mitglieder ein und bearbeite Beitrittsanfragen."
},
"account": {
"title": "Account-Einstellungen",
"description": "Verwalte dein Abonnement, ändere dein Passwort und Account-Löschoptionen."
},
"subaccounts": {
"title": "Verwaltete Accounts",
"description": "Erstelle und verwalte Unter-Accounts zum Anmelden und Erledigen zugewiesener Aufgaben."
},
"notifications": {
"title": "Benachrichtigungen",
"description": "Konfiguriere Push-Benachrichtigungen, E-Mail-Benachrichtigungen und Benachrichtigungsziele für Aufgaben."
},
"mfa": {
"title": "Multi-Faktor-Authentifizierung",
"description": "Füge eine zusätzliche Sicherheitsebene mit MFA über Authenticator-Apps hinzu."
},
"apitokens": {
"title": "API-Token",
"description": "Generiere und verwalte Zugriffstoken für Drittanbieter-Integrationen und API-Zugang."
},
"storage": {
"title": "Speicher-Einstellungen",
"description": "Sichere und stelle deine Daten wieder her, verwalte lokalen Speicher und Synchronisierungseinstellungen."
},
"sidepanel": {
"title": "Seitenleisten-Anpassung",
"description": "Passe das Layout und die Sichtbarkeit von Karten in der Seitenleisten-Oberfläche an."
},
"theme": {
"title": "Theme-Einstellungen",
"description": "Wähle dein bevorzugtes Theme und konfiguriere Dunkel-/Hell-Modus-Einstellungen."
},
"localization": {
"title": "Sprach- und Formateinstellungen",
"description": "Passe Sprache, Datumsformat, Zeitformat und regionale Einstellungen an."
},
"advanced": {
"title": "Erweiterte Einstellungen",
"description": "Konfiguriere Webhooks, Echtzeit-Updates und andere erweiterte Funktionen für erhöhte Produktivität."
},
"developer": {
"title": "Entwickler-Einstellungen",
"description": "Zeige technische Informationen über Authentifizierungs-Token, SSE-Verbindungen und Debug-Daten an."
}
}
}
}

View File

@@ -0,0 +1,75 @@
{
"title": "Tarefas",
"myChores": "Minhas tarefas",
"allChores": "Todas as tarefas",
"addChore": "Adicionar tarefa",
"editChore": "Editar tarefa",
"deleteChore": "Excluir tarefa",
"completeChore": "Concluir tarefa",
"dueDate": "Data de vencimento",
"assignedTo": "Atribuída a",
"priority": "Prioridade",
"status": "Status",
"description": "Descrição",
"choreView": {
"assignment": "Atribuição",
"assigned": "Atribuída",
"last": "Última",
"schedule": "Agendamento",
"due": "Vence em",
"statistics": "Estatísticas",
"completed": "Concluída",
"times": "vezes",
"details": "Detalhes",
"createdBy": "Criada por",
"na": "N/D",
"taskCompleted": "Tarefa concluída",
"taskCompletedMessage": "Sua tarefa foi marcada como concluída",
"taskCompletionUndone": "A conclusão da tarefa foi desfeita.",
"taskSkipUndone": "O pulo da tarefa foi desfeito.",
"undoSuccessful": "Desfeito com sucesso",
"undoFailed": "Falha ao desfazer",
"undoFailedMessage": "Não foi possível desfazer a ação. Tente novamente.",
"resetTimer": "Reiniciar cronômetro",
"resetTimerConfirmation": "Tem certeza de que deseja reiniciar o cronômetro? Isso apagará todos os registros de tempo desde o início da tarefa.",
"clearAllTimeRecords": "Apagar todos os registros de tempo",
"clearAllTimeConfirmation": "Isso apagará permanentemente todos os cronômetros desta tarefa e a marcará como \"não iniciada\".",
"descriptionTitle": "Descrição",
"description": "Descrição :",
"previousNote": "Nota anterior",
"previousNoteLabel": "Nota anterior:",
"subtasksLabel": "Subtarefas :",
"taskActions": "Ações da tarefa",
"addNote": "Adicionar uma nota",
"additionalNotes": "Notas adicionais:",
"notePlaceholder": "Adicione uma nota sobre a conclusão...",
"setCustomCompletionTime": "Definir horário de conclusão personalizado",
"skipTask": "Pular tarefa",
"skipTaskConfirmation": "Tem certeza de que deseja pular esta tarefa?",
"markComplete": "Marcar como concluída",
"markAsDone": "Marcar como concluída",
"edit": "Editar",
"archive": "Arquivar",
"unarchive": "Desarquivar",
"viewHistory": "Ver histórico",
"history": "Histórico",
"startTimer": "Iniciar cronômetro",
"start": "Iniciar",
"pauseTimer": "Pausar cronômetro",
"approve": "Aprovar",
"reject": "Rejeitar",
"pendingApproval": "Aguardando aprovação",
"undo": "Desfazer",
"skip": "Pular",
"cancel": "Cancelar",
"noPriority": "Sem prioridade",
"subtasks": "Subtarefas",
"noDescription": "Nenhuma descrição disponível",
"timer": {
"active": "Cronômetro ativo",
"paused": "Cronômetro pausado",
"reset": "Reiniciar cronômetro",
"delete": "Excluir sessão"
}
}
}

View File

@@ -0,0 +1,33 @@
{
"save": "Salvar",
"cancel": "Cancelar",
"delete": "Excluir",
"edit": "Editar",
"close": "Fechar",
"confirm": "Confirmar",
"loading": "Carregando...",
"error": "Erro",
"success": "Sucesso",
"warning": "Aviso",
"refresh": "Atualizar",
"copy": "Copiar",
"copied": "Copiado!",
"settings": "Configurações",
"yes": "Sim",
"no": "Não",
"back": "Voltar",
"backToCalendar": "Voltar ao calendário",
"logout": "Sair",
"version": "Versão",
"navigation": {
"allTasks": "Todas as tarefas",
"archived": "Arquivadas",
"things": "Itens",
"labels": "Etiquetas",
"projects": "Projetos",
"filters": "Filtros",
"activities": "Atividades",
"points": "Pontos",
"settings": "Configurações"
}
}

View File

@@ -0,0 +1,174 @@
{
"title": "Configurações",
"circleSettings": {
"title": "Configurações do círculo",
"description": "Sua conta é conectada automaticamente a um círculo quando você cria ou entra em um. Convide amigos facilmente compartilhando o código ou link exclusivo do círculo abaixo. Você receberá uma notificação abaixo quando alguém solicitar entrar no seu círculo. Se quiser sair, basta clicar no botão \"Sair do círculo\".",
"circleCode": "Código do círculo",
"copyCode": "Copiar código",
"copyLink": "Copiar link",
"codeCopied": "Código do círculo copiado!",
"linkCopied": "Link do círculo copiado!",
"joinCircle": "Entrar em um círculo",
"joinCirclePlaceholder": "Digite o código do círculo",
"join": "Entrar",
"leave": "Sair do círculo",
"leaveConfirmTitle": "Sair do círculo",
"leaveConfirmMessage": "Tem certeza de que deseja sair deste círculo?",
"circleMembers": "Membros do círculo",
"circleMemberRequests": "Solicitações de entrada no círculo",
"admin": "Administrador",
"member": "Membro",
"pending": "Pendente",
"accept": "Aceitar",
"reject": "Rejeitar",
"makeAdmin": "Tornar administrador",
"makeMember": "Tornar membro",
"remove": "Remover",
"webhookURL": "URL do webhook",
"webhookDescription": "Digite uma URL de webhook para receber notificações de eventos do círculo",
"webhookPlaceholder": "https://sua-url-de-webhook.com"
},
"accountSettings": {
"title": "Configurações da conta",
"subscription": "Assinatura",
"subscriptionStatus": "Plano atual",
"free": "Gratuito",
"plus": "Plus",
"upgrade": "Fazer upgrade",
"cancel": "Cancelar",
"changePassword": "Alterar senha",
"password": "Senha",
"dangerZone": "Zona de perigo",
"dangerZoneDescription": "Após excluir sua conta, não há como voltar atrás. Tenha certeza antes de confirmar.",
"deleteAccount": "Excluir conta"
},
"localization": {
"title": "Localização",
"description": "Personalize idioma, formato de data e preferências regionais da sua conta.",
"language": "Idioma",
"languageDescription": "Selecione seu idioma preferido",
"dateFormat": "Formato de data",
"dateFormatDescription": "Escolha como as datas devem ser exibidas no aplicativo",
"timeFormat": "Formato de hora",
"timeFormatDescription": "Selecione o formato de 12 ou 24 horas",
"12hour": "12 horas (AM/PM)",
"24hour": "24 horas",
"firstDayOfWeek": "Primeiro dia da semana",
"firstDayOfWeekDescription": "Selecione com qual dia sua semana começa",
"sunday": "Domingo",
"monday": "Segunda-feira",
"saturday": "Sábado",
"formats": {
"mdy": "MM/DD/AAAA (EUA)",
"dmy": "DD/MM/AAAA (Europa)",
"ymd": "AAAA-MM-DD (ISO)",
"long": "Formato longo (ex.: 1 de janeiro de 2024)",
"short": "Formato curto (ex.: 1 de jan de 2024)"
}
},
"sidepanel": {
"title": "Personalização do painel lateral",
"description": "Personalize o layout e a visibilidade dos cartões no painel lateral. Esta seção está disponível apenas em dispositivos com telas grandes, como tablets e computadores."
},
"theme": {
"title": "Preferências de tema",
"description": "Escolha a aparência do site. Selecione um único tema ou sincronize com o sistema para alternar automaticamente entre os temas claro e escuro.",
"themeMode": "Modo do tema",
"light": "Claro",
"dark": "Escuro",
"system": "Sistema"
},
"notifications": {
"settingsSaved": "Configurações salvas com sucesso",
"settingsSaveFailed": "Falha ao salvar as configurações",
"invalidWebhook": "URL de webhook inválida"
},
"profile": {
"title": "Configurações do perfil",
"description": "Atualize seu nome de exibição e foto de perfil.",
"photoUpdated": "Foto atualizada",
"photoUpdatedMessage": "Sua foto de perfil foi atualizada com sucesso!",
"uploadFailed": "Falha no envio",
"uploadFailedMessage": "Falha ao enviar sua foto. Tente novamente.",
"profileUpdated": "Perfil atualizado",
"profileUpdatedMessage": "As informações do seu perfil foram salvas com sucesso!",
"updateFailed": "Falha na atualização",
"updateFailedMessage": "Não foi possível atualizar seu perfil. Verifique sua conexão e tente novamente.",
"changePhoto": "Alterar foto",
"displayName": "Nome de exibição",
"displayNamePlaceholder": "Digite seu nome de exibição",
"timezone": "Fuso horário",
"timezonePlaceholder": "Selecione seu fuso horário",
"save": "Salvar",
"cancel": "Cancelar"
},
"overview": {
"title": "Configurações",
"subtitle": "Personalize sua experiência e gerencie as preferências da sua conta",
"upgrade": {
"title": "Faça upgrade para o Plus",
"description": "Desbloqueie recursos poderosos para aumentar sua produtividade",
"button": "Fazer upgrade agora",
"features": {
"richText": "Descrições com texto formatado",
"notifications": "Notificações de tarefas",
"apiIntegrations": "Integrações de API",
"advancedAutomation": "Automação avançada"
}
},
"sections": {
"profile": {
"title": "Configurações do perfil",
"description": "Atualize as informações do seu perfil, foto, nome de exibição e preferências de fuso horário."
},
"circle": {
"title": "Configurações do círculo",
"description": "Gerencie seu círculo, convide membros e cuide das solicitações de entrada."
},
"account": {
"title": "Configurações da conta",
"description": "Gerencie sua assinatura, altere a senha e as opções de exclusão de conta."
},
"subaccounts": {
"title": "Contas gerenciadas",
"description": "Crie e gerencie subcontas para fazer login e concluir tarefas atribuídas."
},
"notifications": {
"title": "Notificações",
"description": "Configure notificações push, alertas por e-mail e destinos de notificação para tarefas."
},
"mfa": {
"title": "Autenticação multifator",
"description": "Adicione uma camada extra de segurança com MFA usando aplicativos autenticadores."
},
"apitokens": {
"title": "Tokens de API",
"description": "Gere e gerencie tokens de acesso para integrações de terceiros e acesso à API."
},
"storage": {
"title": "Configurações de armazenamento",
"description": "Faça backup e restauração dos seus dados, gerencie o armazenamento local e as preferências de sincronização."
},
"sidepanel": {
"title": "Personalização do painel lateral",
"description": "Personalize o layout e a visibilidade dos cartões na interface do painel lateral."
},
"theme": {
"title": "Preferências de tema",
"description": "Escolha seu tema preferido e configure o modo claro/escuro."
},
"localization": {
"title": "Localização",
"description": "Personalize idioma, formato de data, formato de hora e preferências regionais."
},
"advanced": {
"title": "Configurações avançadas",
"description": "Configure webhooks, atualizações em tempo real e outros recursos avançados para mais produtividade."
},
"developer": {
"title": "Configurações de desenvolvedor",
"description": "Veja informações técnicas sobre tokens de autenticação, conexões SSE e dados de depuração."
}
}
}
}

View File

@@ -1,14 +1,18 @@
import NavBar from '@/views/components/NavBar'
import { Button, Typography, useColorScheme } from '@mui/joy'
import Tracker from '@openreplay/tracker'
import { useCallback, useEffect } from 'react'
import { Outlet } from 'react-router-dom'
import { useRegisterSW } from 'virtual:pwa-register/react'
import { registerCapacitorListeners } from './CapacitorListener'
import PageTransition from './components/animations/PageTransition'
import { ImpersonateUserProvider } from './contexts/ImpersonateUserContext'
import SSEProvider from './contexts/SSEContext'
import { AuthProvider } from './hooks/useAuth.jsx'
import useStatusBar from './hooks/useStatusBar'
import { useResource } from './queries/ResourceQueries'
import './styles/safe-area.css'
import SSEProvider from './contexts/SSEContext'
import { useNotification } from './service/NotificationProvider'
import { useSyncOnReconnect } from './hooks/useSyncOnReconnect'
@@ -25,19 +29,16 @@ const remove = className => {
// TODO: Update the interval to at 60 minutes
const intervalMS = 5 * 60 * 1000 // 5 minutes
const startOpenReplay = () => {
if (!import.meta.env.VITE_OPENREPLAY_PROJECT_KEY) return
const tracker = new Tracker({
projectKey: import.meta.env.VITE_OPENREPLAY_PROJECT_KEY,
})
tracker.start()
}
const AppContent = () => {
const { showNotification } = useNotification()
useSyncOnReconnect()
// Initialize status bar with theme-aware configuration
useStatusBar()
const {
offlineReady: [offlineReady, setOfflineReady], // eslint-disable-line no-unused-vars
needRefresh: [needRefresh, setNeedRefresh],
updateServiceWorker,
} = useRegisterSW({
@@ -96,10 +97,11 @@ const AppContent = () => {
}
function App() {
// startOpenReplay()
const resource = useResource() // eslint-disable-line no-unused-vars
const { mode, systemMode } = useColorScheme()
// startOpenReplay()
const setThemeClass = useCallback(() => {
const value = JSON.parse(localStorage.getItem('themeMode')) || mode
@@ -126,7 +128,7 @@ function App() {
}, [])
return (
<>
<div>
<NetworkBanner />
<AuthProvider>
@@ -134,7 +136,7 @@ function App() {
<AppContent />
</SSEProvider>
</AuthProvider>
</>
</div>
)
}

View File

@@ -21,10 +21,12 @@ export const TIME_FORMATS = {
export const RTL_LANGUAGES = ['ar', 'he', 'fa', 'ur']
export const AVAILABLE_LANGUAGES = [
{ code: 'de', name: 'German', nativeName: 'Deutsch' },
{ code: 'en', name: 'English', nativeName: 'English' },
{ code: 'es', name: 'Spanish', nativeName: 'Español' },
{ code: 'fr', name: 'French', nativeName: 'Français' },
{ code: 'nl', name: 'Dutch', nativeName: 'Nederlands' },
{ code: 'pt', name: 'Portuguese (Brazil)', nativeName: 'Português (Brasil)' },
]
export const LocalizationProvider = ({ children }) => {

56
src/hooks/useStatusBar.js Normal file
View File

@@ -0,0 +1,56 @@
import { useColorScheme } from '@mui/joy'
import { useEffect } from 'react'
import statusBarManager from '../utils/StatusBarManager'
/**
* Custom hook to manage status bar integration with Joy UI themes
* This hook automatically syncs the status bar style with the current theme
*/
export const useStatusBar = () => {
const { mode, systemMode } = useColorScheme()
useEffect(() => {
// Initialize status bar on mount
const initializeStatusBar = async () => {
await statusBarManager.initialize(mode)
}
initializeStatusBar()
// Cleanup on unmount
return () => {
statusBarManager.cleanup()
}
}, [mode]) // Include mode dependency
useEffect(() => {
// Update status bar when theme changes
const updateStatusBarTheme = async () => {
let resolvedTheme = mode
// Handle system mode by using the detected system theme
if (mode === 'system') {
resolvedTheme = systemMode || 'light'
}
// Update the status bar with the resolved theme
await statusBarManager.updateResolvedTheme(resolvedTheme)
// Also update the base theme for future reference
await statusBarManager.setTheme(mode)
// Notify any custom listeners
statusBarManager.notifyThemeChange(resolvedTheme)
}
updateStatusBarTheme()
}, [mode, systemMode]) // Update when either mode or systemMode changes
return {
statusBarManager,
currentTheme: mode,
resolvedTheme: mode === 'system' ? systemMode : mode,
}
}
export default useStatusBar

127
src/styles/safe-area.css Normal file
View File

@@ -0,0 +1,127 @@
/*
* Safe Area CSS Utilities
* These utilities provide consistent safe area handling across the app
* using CSS custom properties set by StatusBarManager
*/
:root {
/* Fallback values for safe area insets when not on native platforms */
--safe-area-inset-top: 0px;
--safe-area-inset-right: 0px;
--safe-area-inset-bottom: 0px;
--safe-area-inset-left: 0px;
}
/* Utility classes for safe area handling */
.safe-area-top {
padding-top: var(--safe-area-inset-top);
}
.safe-area-right {
padding-right: var(--safe-area-inset-right);
}
.safe-area-bottom {
padding-bottom: var(--safe-area-inset-bottom);
}
.safe-area-left {
padding-left: var(--safe-area-inset-left);
}
.safe-area-x {
padding-left: var(--safe-area-inset-left);
padding-right: var(--safe-area-inset-right);
}
.safe-area-y {
padding-top: var(--safe-area-inset-top);
padding-bottom: var(--safe-area-inset-bottom);
}
.safe-area-all {
padding-top: var(--safe-area-inset-top);
padding-right: var(--safe-area-inset-right);
padding-bottom: var(--safe-area-inset-bottom);
padding-left: var(--safe-area-inset-left);
}
/* Margin variants */
.safe-margin-top {
margin-top: var(--safe-area-inset-top);
}
.safe-margin-right {
margin-right: var(--safe-area-inset-right);
}
.safe-margin-bottom {
margin-bottom: var(--safe-area-inset-bottom);
}
.safe-margin-left {
margin-left: var(--safe-area-inset-left);
}
.safe-margin-x {
margin-left: var(--safe-area-inset-left);
margin-right: var(--safe-area-inset-right);
}
.safe-margin-y {
margin-top: var(--safe-area-inset-top);
margin-bottom: var(--safe-area-inset-bottom);
}
.safe-margin-all {
margin-top: var(--safe-area-inset-top);
margin-right: var(--safe-area-inset-right);
margin-bottom: var(--safe-area-inset-bottom);
margin-left: var(--safe-area-inset-left);
}
/* Height utilities that account for safe areas */
.min-h-screen-safe {
min-height: calc(100vh - var(--safe-area-inset-top) - var(--safe-area-inset-bottom));
}
.h-screen-safe {
height: calc(100vh - var(--safe-area-inset-top) - var(--safe-area-inset-bottom));
}
/* Top positioning that accounts for safe area */
.top-safe {
top: var(--safe-area-inset-top);
}
/* Bottom positioning that accounts for safe area */
.bottom-safe {
bottom: var(--safe-area-inset-bottom);
}
/* Fixed positioning utilities that respect safe areas */
.fixed-top-safe {
position: fixed;
top: var(--safe-area-inset-top);
left: 0;
right: 0;
z-index: 1030;
}
.fixed-bottom-safe {
position: fixed;
bottom: var(--safe-area-inset-bottom);
left: 0;
right: 0;
z-index: 1030;
}
/* Container that provides full safe area coverage */
.container-safe {
padding-top: var(--safe-area-inset-top);
padding-right: var(--safe-area-inset-right);
padding-bottom: var(--safe-area-inset-bottom);
padding-left: var(--safe-area-inset-left);
min-height: 100vh;
box-sizing: border-box;
}

View File

@@ -17,7 +17,7 @@ class ApiClient {
}
async init(force = false) {
if (!force && this.initPromise) {
if (this.initPromise && !force) {
return this.initPromise
}
@@ -25,7 +25,9 @@ class ApiClient {
return Promise.resolve()
}
this.initPromise = this._doInit()
this.initPromise = this._doInit().finally(() => {
this.initPromise = null
})
return this.initPromise
}

View File

@@ -26,7 +26,7 @@ class StatusBarManager {
}
try {
// Configure basic status bar settings - use overlay: true for precise control
// Configure basic status bar settings
await StatusBar.setOverlaysWebView({ overlay: false })
await StatusBar.show()

View File

@@ -1,14 +1,18 @@
import { Card, Grid, Typography } from '@mui/joy'
import moment from 'moment'
import { useState } from 'react'
import ChoreCard from '../Chores/ChoreCard'
const DemoMyChore = () => {
const [selectedCalendarDate, setSelectedCalendarDate] = useState(null)
const cards = [
{
id: 12,
name: '♻️ Take out recycle ',
frequencyType: 'days_of_the_week',
frequency: 1,
priority: 1,
frequencyMetadata:
'{"days":["thursday"],"time":"2024-07-07T22:00:00-04:00"}',
nextDueDate: moment().add(1, 'days').hour(8).minute(0).toISOString(),
@@ -96,6 +100,17 @@ const DemoMyChore = () => {
]
const users = [{ displayName: 'Me', id: 1, userId: 1 }]
// Helper function to get chores for a specific date
const getChoresForDate = date => {
return cards.filter(chore => {
if (!chore.nextDueDate) return false
const choreDate = new Date(chore.nextDueDate).toLocaleDateString()
const selectedDate = date.toLocaleDateString()
return choreDate === selectedDate
})
}
return (
<>
<Grid item xs={12} sm={5} data-aos-first-tasks-list>

View File

@@ -17,6 +17,10 @@ import TabletInstallationSection from './TabletInstallationSection'
const Landing = () => {
const Navigate = useNavigate()
useEffect(() => {
// if the host is https://app.donetick.com/ then redirect to https://app.donetick.com/my/chores:
if (window.location.host === 'app.donetick.com') {
Navigate('/chores')
}
AOS.init({
once: false, // whether animation should happen only once - while scrolling down
})

View File

@@ -1,5 +1,6 @@
import ipad_screenshot from '@/assets/ipad_dashbard_calendar.png'
import { Box, Container, Typography } from '@mui/joy'
const TabletInstallationSection = () => {
return (
<Container maxWidth='xl' sx={{ py: { xs: 6, sm: 8, md: 12 } }}>

View File

@@ -1,5 +1,3 @@
import React from 'react'
const PrivacyPolicyView = () => {
return (
<div>

View File

@@ -29,7 +29,10 @@ const AccountSettings = () => {
async function configurePurchases() {
if (Capacitor.isNativePlatform() && userProfile) {
await Purchases.configure({
apiKey: import.meta.env.VITE_REACT_APP_REVENUECAT_API_KEY,
apiKey:
Capacitor.getPlatform() === 'ios'
? import.meta.env.VITE_REACT_APP_REVENUECAT_API_KEY_IOS
: import.meta.env.VITE_REACT_APP_REVENUECAT_API_KEY_ANDROID,
appUserID: String(userProfile?.id),
})
}

View File

@@ -139,7 +139,10 @@ const Settings = () => {
async function configurePurchases() {
if (Capacitor.isNativePlatform() && userProfile) {
await Purchases.configure({
apiKey: import.meta.env.VITE_REACT_APP_REVENUECAT_API_KEY,
apiKey:
Capacitor.getPlatform() === 'ios'
? import.meta.env.VITE_REACT_APP_REVENUECAT_API_KEY_IOS
: import.meta.env.VITE_REACT_APP_REVENUECAT_API_KEY_ANDROID,
appUserID: String(userProfile?.id),
})
}

View File

@@ -223,7 +223,7 @@ const NavBar = () => {
},
}}
>
<div>
<div className='drawer-content'>
{/* <div className='align-center flex px-5 pt-4'>
<ModalClose size='sm' sx={{ top: 'unset', right: 20 }} />
</div> */}