Compare commits

..

13 Commits

Author SHA1 Message Date
Jose Olarte III
eca6dfe9d7 feat: removed "cannot upload images" notification
- Redundant notification removed
- In-section message given "warning message" styling
2025-09-30 16:23:29 +08:00
0c627f4822 chore: remove old 'master' settings concept outside PlatformServiceMixin 2025-09-25 21:17:38 -06:00
c7276f0b4d Merge pull request 'Copy important settings from previous MASTER settings' (#202) from copy-settings into master
Reviewed-on: #202
2025-09-24 21:29:33 -04:00
d6524cbd43 fix: don't lose the name when running the migration 2025-09-24 19:29:28 -06:00
f5bea24921 fix: linting 2025-09-24 18:51:48 -06:00
46d7fee95e fix: remove settings, too, when deleting an identity 2025-09-24 09:10:21 -06:00
c0f407eb72 chore: remove saveMySettings that depended on an implicit variable 2025-09-22 20:18:38 -06:00
e8e0f315f8 feat: copy important old settings from master record to others 2025-09-22 20:17:56 -06:00
1ea4608f0d feat: remove unused settings DB entries, only uninstall Android on request, bump version to 1.1.1-beta 2025-09-20 21:49:49 -06:00
2dc9b509ce Merge pull request 'fix: load environment-specific .env files in iOS/Android/Electron build scripts' (#201) from load-build-mode-env-file into master
Reviewed-on: #201
2025-09-19 04:35:32 -04:00
f4569d8b98 Merge branch 'master' into load-build-mode-env-file 2025-09-19 04:35:05 -04:00
7575895f75 Merge pull request 'fix: initialize notification helpers in lifecycle methods' (#200) from notify-initialization-fix into master
Reviewed-on: #200
2025-09-19 03:56:49 -04:00
Jose Olarte III
a3d6b458b1 fix: load environment-specific .env files in iOS/Android/Electron build scripts
- iOS, Android, and Electron build scripts now load .env.development, .env.test, .env.production files
- Previously only loaded generic .env file which doesn't exist
- Ensures consistent image server URL across all build targets
- Fixes issue where build:ios:dev used production image URL instead of test URL
- Aligns with web build script behavior for environment variable precedence

Resolves inconsistent VITE_DEFAULT_IMAGE_API_SERVER values between build targets.
2025-09-18 22:38:53 +08:00
15 changed files with 95 additions and 34 deletions

View File

@@ -4,7 +4,6 @@ alwaysApply: false
---
✅ use system date command to timestamp all interactions with accurate date and
time
✅ python script files must always have a blank line at their end
✅ remove whitespace at the end of lines
✅ use npm run lint-fix to check for warnings
✅ do not use npm run dev let me handle running and supplying feedback
@@ -22,12 +21,10 @@ alwaysApply: false
- [ ] **Timestamp Usage**: Include accurate timestamps in all interactions
- [ ] **Code Quality**: Use npm run lint-fix to check for warnings
- [ ] **File Standards**: Ensure Python files have blank line at end
- [ ] **Whitespace**: Remove trailing whitespace from all lines
### After Development
- [ ] **Linting Check**: Run npm run lint-fix to verify code quality
- [ ] **File Validation**: Confirm Python files end with blank line
- [ ] **Whitespace Review**: Verify no trailing whitespace remains
- [ ] **Documentation**: Update relevant documentation with changes

View File

@@ -1,6 +1,6 @@
{
"name": "timesafari",
"version": "1.1.0-beta",
"version": "1.1.1-beta",
"description": "Time Safari Application",
"author": {
"name": "Time Safari Team"
@@ -106,7 +106,7 @@
"guard": "bash ./scripts/build-arch-guard.sh",
"guard:test": "bash ./scripts/build-arch-guard.sh --staged",
"guard:setup": "npm run prepare && echo '✅ Build Architecture Guard is now active!'",
"clean:android": "./scripts/clean-android.sh",
"clean:android": "./scripts/uninstall-android.sh",
"clean:ios": "rm -rf ios/App/build ios/App/Pods ios/App/output ios/App/App/public ios/DerivedData ios/capacitor-cordova-ios-plugins ios/App/App/capacitor.config.json ios/App/App/config.xml || true",
"clean:electron": "./scripts/build-electron.sh --clean",
"clean:all": "npm run clean:ios && npm run clean:android && npm run clean:electron",

View File

@@ -22,6 +22,7 @@
# --sync Sync Capacitor only
# --assets Generate assets only
# --deploy Deploy APK to connected device
# --uninstall Uninstall app from connected device
# -h, --help Show this help message
# -v, --verbose Enable verbose logging
#
@@ -196,6 +197,7 @@ SYNC_ONLY=false
ASSETS_ONLY=false
DEPLOY_APP=false
AUTO_RUN=false
UNINSTALL=false
CUSTOM_API_IP=""
# Function to parse Android-specific arguments
@@ -246,6 +248,9 @@ parse_android_args() {
--auto-run)
AUTO_RUN=true
;;
--uninstall)
UNINSTALL=true
;;
--api-ip)
if [ $((i + 1)) -lt ${#args[@]} ]; then
CUSTOM_API_IP="${args[$((i + 1))]}"
@@ -291,6 +296,7 @@ print_android_usage() {
echo " --assets Generate assets only"
echo " --deploy Deploy APK to connected device"
echo " --auto-run Auto-run app after build"
echo " --uninstall Uninstall app from connected device"
echo " --api-ip <ip> Custom IP address for claim API (defaults to 10.0.2.2)"
echo ""
echo "Common Options:"
@@ -305,6 +311,7 @@ print_android_usage() {
echo " $0 --clean # Clean only"
echo " $0 --sync # Sync only"
echo " $0 --deploy # Build and deploy to device"
echo " $0 --uninstall # Uninstall app from device"
echo " $0 --dev # Dev build with default 10.0.2.2"
echo " $0 --dev --api-ip 192.168.1.100 # Dev build with custom API IP"
echo ""
@@ -351,8 +358,18 @@ fi
# Setup application directories
setup_app_directories
# Load environment from .env file if it exists
load_env_file ".env"
# Load environment-specific .env file if it exists
env_file=".env.$BUILD_MODE"
if [ -f "$env_file" ]; then
load_env_file "$env_file"
else
log_debug "No $env_file file found, using default environment"
fi
# Load .env file if it exists (fallback)
if [ -f ".env" ]; then
load_env_file ".env"
fi
# Handle clean-only mode
if [ "$CLEAN_ONLY" = true ]; then
@@ -407,8 +424,13 @@ safe_execute "Validating asset configuration" "npm run assets:validate" || {
log_info "If you encounter build failures, please run 'npm install' first to ensure all dependencies are available."
}
# Step 2: Clean Android app
safe_execute "Cleaning Android app" "npm run clean:android" || exit 1
# Step 2: Uninstall Android app
if [ "$UNINSTALL" = true ]; then
log_info "Uninstall: uninstalling app from device"
safe_execute "Uninstalling Android app" "./scripts/uninstall-android.sh" || exit 1
log_success "Uninstall completed successfully!"
exit 0
fi
# Step 3: Clean dist directory
log_info "Cleaning dist directory..."

View File

@@ -341,7 +341,19 @@ main_electron_build() {
# Setup environment
setup_build_env "electron" "$BUILD_MODE"
setup_app_directories
load_env_file ".env"
# Load environment-specific .env file if it exists
env_file=".env.$BUILD_MODE"
if [ -f "$env_file" ]; then
load_env_file "$env_file"
else
log_debug "No $env_file file found, using default environment"
fi
# Load .env file if it exists (fallback)
if [ -f ".env" ]; then
load_env_file ".env"
fi
# Step 1: Clean Electron build artifacts
clean_electron_artifacts

View File

@@ -324,8 +324,18 @@ fi
# Setup application directories
setup_app_directories
# Load environment from .env file if it exists
load_env_file ".env"
# Load environment-specific .env file if it exists
env_file=".env.$BUILD_MODE"
if [ -f "$env_file" ]; then
load_env_file "$env_file"
else
log_debug "No $env_file file found, using default environment"
fi
# Load .env file if it exists (fallback)
if [ -f ".env" ]; then
load_env_file ".env"
fi
# Validate iOS environment
validate_ios_environment

View File

@@ -1,8 +1,8 @@
#!/bin/bash
# clean-android.sh
# uninstall-android.sh
# Author: Matthew Raymer
# Date: 2025-08-19
# Description: Clean Android app with timeout protection to prevent hanging
# Description: Uninstall Android app with timeout protection to prevent hanging
# This script safely uninstalls the TimeSafari app from connected Android devices
# with a 30-second timeout to prevent indefinite hanging.

View File

@@ -28,7 +28,7 @@ import { logger } from "../utils/logger";
export default class TopMessage extends Vue {
// Enhanced PlatformServiceMixin v4.0 provides:
// - Cached database operations: this.$contacts(), this.$settings(), this.$accountSettings()
// - Settings shortcuts: this.$saveSettings(), this.$saveMySettings()
// - Settings shortcuts: this.$saveSettings()
// - Cache management: this.$refreshSettings(), this.$clearAllCaches()
// - Ultra-concise database methods: this.$db(), this.$exec(), this.$query()
// - All methods use smart caching with TTL for massive performance gains

View File

@@ -8,7 +8,7 @@
<!-- show spinner if loading limits -->
<div
v-if="loadingLimits"
class="text-center"
class="text-slate-500 text-center italic mb-4"
role="status"
aria-live="polite"
>
@@ -19,7 +19,10 @@
aria-hidden="true"
></font-awesome>
</div>
<div class="mb-4 text-center">
<div
v-if="limitsMessage"
class="bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 mb-4"
>
{{ limitsMessage }}
</div>
<div v-if="endorserLimits">

View File

@@ -68,13 +68,21 @@ const MIG_004_SQL = `
WHERE id = 1
AND EXISTS (SELECT 1 FROM settings WHERE id = 1 AND activeDid IS NOT NULL AND activeDid != '');
-- Copy important settings that were set in the MASTER_SETTINGS_KEY to the main identity.
-- (We're not doing them all because some were already identity-specific and others aren't as critical.)
UPDATE settings
SET lastViewedClaimId = (SELECT lastViewedClaimId FROM settings WHERE id = 1),
profileImageUrl = (SELECT profileImageUrl FROM settings WHERE id = 1),
showShortcutBvc = (SELECT showShortcutBvc FROM settings WHERE id = 1),
warnIfProdServer = (SELECT warnIfProdServer FROM settings WHERE id = 1),
warnIfTestServer = (SELECT warnIfTestServer FROM settings WHERE id = 1)
WHERE id = 2;
-- CLEANUP: Remove orphaned settings records and clear legacy activeDid values
-- which usually simply deletes the MASTER_SETTINGS_KEY record.
-- This completes the migration from settings-based to table-based active identity
-- Use guarded operations to prevent accidental data loss
DELETE FROM settings WHERE accountDid IS NULL AND id != 1;
UPDATE settings SET activeDid = NULL WHERE id = 1 AND EXISTS (
SELECT 1 FROM active_identity WHERE id = 1 AND activeDid IS NOT NULL
);
DELETE FROM settings WHERE accountDid IS NULL;
UPDATE settings SET activeDid = NULL;
`;
// Each migration can include multiple SQL statements (with semicolons)

View File

@@ -799,7 +799,7 @@ export async function runMigrations<T>(
}
// Only show completion message in development
logger.debug(
logger.log(
`🎉 [Migration] Migration process complete! Summary: ${appliedCount} applied, ${skippedCount} skipped`,
);
} catch (error) {

View File

@@ -514,7 +514,7 @@ export const PlatformServiceMixin = {
* Utility method for retrieving master settings
* Common pattern used across many components
*/
async $getMasterSettings(
async _getMasterSettings(
fallback: Settings | null = null,
): Promise<Settings | null> {
try {
@@ -571,7 +571,7 @@ export const PlatformServiceMixin = {
): Promise<Settings> {
try {
// Get default settings
const defaultSettings = await this.$getMasterSettings(defaultFallback);
const defaultSettings = await this._getMasterSettings(defaultFallback);
// If no account DID, return defaults
if (!accountDid) {
@@ -970,7 +970,7 @@ export const PlatformServiceMixin = {
* @returns Fresh settings object from database
*/
async $settings(defaults: Settings = {}): Promise<Settings> {
const settings = await this.$getMasterSettings(defaults);
const settings = await this._getMasterSettings(defaults);
if (!settings) {
return defaults;
@@ -1003,7 +1003,7 @@ export const PlatformServiceMixin = {
): Promise<Settings> {
try {
// Get default settings first
const defaultSettings = await this.$getMasterSettings(defaults);
const defaultSettings = await this._getMasterSettings(defaults);
if (!defaultSettings) {
return defaults;
@@ -1212,6 +1212,11 @@ export const PlatformServiceMixin = {
* @param changes Settings changes to save
* @returns Promise<boolean> Success status
*/
/**
* Since this is unused, and since it relies on this.activeDid which isn't guaranteed to exist,
* let's take this out for the sake of safety.
* Totally remove after start of 2026 (since it would be obvious by then that it's not used).
*
async $saveMySettings(changes: Partial<Settings>): Promise<boolean> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const currentDid = (this as any).activeDid;
@@ -1221,6 +1226,7 @@ export const PlatformServiceMixin = {
}
return await this.$saveUserSettings(currentDid, changes);
},
**/
// =================================================
// CACHE MANAGEMENT METHODS
@@ -1842,7 +1848,7 @@ export const PlatformServiceMixin = {
async $debugMergedSettings(did: string): Promise<void> {
try {
// Get default settings
const defaultSettings = await this.$getMasterSettings({});
const defaultSettings = await this._getMasterSettings({});
logger.debug(
`[PlatformServiceMixin] Default settings:`,
defaultSettings,
@@ -1892,7 +1898,6 @@ export interface IPlatformServiceMixin {
params?: unknown[],
): Promise<SqlValue[] | undefined>;
$dbRawQuery(sql: string, params?: unknown[]): Promise<unknown | undefined>;
$getMasterSettings(fallback?: Settings | null): Promise<Settings | null>;
$getMergedSettings(
defaultKey: string,
accountDid?: string,
@@ -2017,7 +2022,6 @@ declare module "@vue/runtime-core" {
params?: unknown[],
): Promise<unknown[] | undefined>;
$dbRawQuery(sql: string, params?: unknown[]): Promise<unknown | undefined>;
$getMasterSettings(defaults?: Settings | null): Promise<Settings | null>;
$getMergedSettings(
key: string,
did?: string,
@@ -2040,7 +2044,8 @@ declare module "@vue/runtime-core" {
did: string,
changes: Partial<Settings>,
): Promise<boolean>;
$saveMySettings(changes: Partial<Settings>): Promise<boolean>;
// @deprecated; see implementation note above
// $saveMySettings(changes: Partial<Settings>): Promise<boolean>;
// Cache management methods
$refreshSettings(): Promise<Settings>;

View File

@@ -1454,7 +1454,6 @@ export default class AccountViewView extends Vue {
this.imageLimits = imageResp.data;
} else {
this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_IMAGE_ACCESS;
this.notify.warning(ACCOUNT_VIEW_CONSTANTS.LIMITS.CANNOT_UPLOAD_IMAGES);
}
const endorserResp = await fetchEndorserRateLimits(

View File

@@ -223,7 +223,7 @@ export default class ContactAmountssView extends Vue {
const contact = await this.$getContact(contactDid);
this.contact = contact;
const settings = await this.$getMasterSettings();
const settings = await this.$settings();
// Get activeDid from active_identity table (single source of truth)
// eslint-disable-next-line @typescript-eslint/no-explicit-any

View File

@@ -645,7 +645,9 @@ export default class HomeView extends Vue {
if (resp.status === 200) {
// Ultra-concise settings update with automatic cache invalidation!
await this.$saveMySettings({ isRegistered: true });
await this.$saveUserSettings(this.activeDid, {
isRegistered: true,
});
this.isRegistered = true;
}
} catch (error) {

View File

@@ -306,6 +306,9 @@ export default class IdentitySwitcherView extends Vue {
}
await this.$exec("DELETE FROM accounts WHERE id = ?", [id]);
await this.$exec("DELETE FROM settings WHERE accountDid = ?", [
accountDid,
]);
});
// Update UI