Merge branch 'master' into ios-2
This commit is contained in:
890
www/index.html
890
www/index.html
@@ -17,627 +17,417 @@
|
||||
color: white;
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
font-size: 2.5em;
|
||||
}
|
||||
.section {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.section h2 {
|
||||
margin-top: 0;
|
||||
color: #ffd700;
|
||||
}
|
||||
.button {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
color: white;
|
||||
padding: 12px 24px;
|
||||
margin: 8px;
|
||||
border-radius: 20px;
|
||||
padding: 15px 30px;
|
||||
margin: 10px;
|
||||
border-radius: 25px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-size: 16px;
|
||||
transition: all 0.3s ease;
|
||||
display: inline-block;
|
||||
}
|
||||
.button:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
.status {
|
||||
margin-top: 15px;
|
||||
padding: 15px;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 8px;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
white-space: pre-wrap;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.success { color: #4CAF50; }
|
||||
.error { color: #f44336; }
|
||||
.warning { color: #ff9800; }
|
||||
.info { color: #2196F3; }
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 15px;
|
||||
margin: 15px 0;
|
||||
}
|
||||
.input-group {
|
||||
margin: 10px 0;
|
||||
}
|
||||
.input-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.input-group input, .input-group select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
margin-top: 30px;
|
||||
padding: 20px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: white;
|
||||
}
|
||||
.input-group input::placeholder {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
border-radius: 10px;
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🔔 DailyNotification Plugin Test</h1>
|
||||
<div id="statusCard" class="status" style="margin-bottom: 20px; font-size: 14px;">
|
||||
<strong>Plugin Status</strong><br>
|
||||
<div style="margin-top: 10px;">
|
||||
⚙️ Plugin Settings: <span id="configStatus">Not configured</span><br>
|
||||
🔌 Native Fetcher: <span id="fetcherStatus">Not configured</span><br>
|
||||
🔔 Notifications: <span id="notificationPermStatus">Checking...</span><br>
|
||||
⏰ Exact Alarms: <span id="exactAlarmPermStatus">Checking...</span><br>
|
||||
📢 Channel: <span id="channelStatus">Checking...</span><br>
|
||||
<div id="pluginStatusContent" style="margin-top: 8px;">
|
||||
Loading plugin status...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Plugin Status Section -->
|
||||
<div class="section">
|
||||
<h2>📊 Plugin Status</h2>
|
||||
<div class="grid">
|
||||
<button class="button" onclick="checkPluginAvailability()">Check Availability</button>
|
||||
<button class="button" onclick="getNotificationStatus()">Get Status</button>
|
||||
<button class="button" onclick="checkPermissions()">Check Permissions</button>
|
||||
<button class="button" onclick="getBatteryStatus()">Battery Status</button>
|
||||
</div>
|
||||
<div id="status" class="status">Ready to test...</div>
|
||||
</div>
|
||||
|
||||
<!-- Permission Management Section -->
|
||||
<div class="section">
|
||||
<h2>🔐 Permission Management</h2>
|
||||
<div class="grid">
|
||||
<button class="button" onclick="requestPermissions()">Request Permissions</button>
|
||||
<button class="button" onclick="requestExactAlarmPermission()">Request Exact Alarm</button>
|
||||
<button class="button" onclick="openExactAlarmSettings()">Open Settings</button>
|
||||
<button class="button" onclick="requestBatteryOptimizationExemption()">Battery Exemption</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notification Scheduling Section -->
|
||||
<div class="section">
|
||||
<h2>⏰ Notification Scheduling</h2>
|
||||
<div class="input-group">
|
||||
<label for="notificationUrl">Content URL:</label>
|
||||
<input type="text" id="notificationUrl" placeholder="https://api.example.com/daily-content" value="https://api.example.com/daily-content">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="notificationTime">Schedule Time:</label>
|
||||
<input type="time" id="notificationTime" value="09:00">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="notificationTitle">Title:</label>
|
||||
<input type="text" id="notificationTitle" placeholder="Daily Notification" value="Daily Notification">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="notificationBody">Body:</label>
|
||||
<input type="text" id="notificationBody" placeholder="Your daily content is ready!" value="Your daily content is ready!">
|
||||
</div>
|
||||
<div class="grid">
|
||||
<button class="button" onclick="scheduleNotification()">Schedule Notification</button>
|
||||
<button class="button" onclick="cancelAllNotifications()">Cancel All</button>
|
||||
<button class="button" onclick="getLastNotification()">Get Last</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Configuration Section -->
|
||||
<div class="section">
|
||||
<h2>⚙️ Plugin Configuration</h2>
|
||||
<div class="input-group">
|
||||
<label for="configUrl">Fetch URL:</label>
|
||||
<input type="text" id="configUrl" placeholder="https://api.example.com/content" value="https://api.example.com/content">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="configTime">Schedule Time:</label>
|
||||
<input type="time" id="configTime" value="09:00">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="configRetryCount">Retry Count:</label>
|
||||
<input type="number" id="configRetryCount" value="3" min="0" max="10">
|
||||
</div>
|
||||
<div class="grid">
|
||||
<button class="button" onclick="configurePlugin()">Configure Plugin</button>
|
||||
<button class="button" onclick="updateSettings()">Update Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Advanced Features Section -->
|
||||
<div class="section">
|
||||
<h2>🚀 Advanced Features</h2>
|
||||
<div class="grid">
|
||||
<button class="button" onclick="getExactAlarmStatus()">Exact Alarm Status</button>
|
||||
<button class="button" onclick="getRebootRecoveryStatus()">Reboot Recovery</button>
|
||||
<button class="button" onclick="getRollingWindowStats()">Rolling Window</button>
|
||||
<button class="button" onclick="maintainRollingWindow()">Maintain Window</button>
|
||||
<button class="button" onclick="getContentCache()">Content Cache</button>
|
||||
<button class="button" onclick="clearContentCache()">Clear Cache</button>
|
||||
<button class="button" onclick="getContentHistory()">Content History</button>
|
||||
<button class="button" onclick="getDualScheduleStatus()">Dual Schedule</button>
|
||||
</div>
|
||||
<button class="button" onclick="requestPermissions()">Request Permissions</button>
|
||||
<button class="button" onclick="testNotification()">Test Notification</button>
|
||||
<button class="button" onclick="checkComprehensiveStatus()">Full System Status</button>
|
||||
|
||||
<div id="status" class="status">
|
||||
Ready to test...
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
console.log('🔔 DailyNotification Plugin Test Interface Loading...');
|
||||
console.log('Script loading...');
|
||||
console.log('JavaScript is working!');
|
||||
|
||||
// Global variables
|
||||
let plugin = null;
|
||||
let isPluginAvailable = false;
|
||||
// Use real DailyNotification plugin
|
||||
console.log('Using real DailyNotification plugin...');
|
||||
window.DailyNotification = window.Capacitor.Plugins.DailyNotification;
|
||||
|
||||
// Initialize plugin on page load
|
||||
document.addEventListener('DOMContentLoaded', async function() {
|
||||
console.log('📱 DOM loaded, initializing plugin...');
|
||||
await initializePlugin();
|
||||
});
|
||||
|
||||
// Initialize the real DailyNotification plugin
|
||||
async function initializePlugin() {
|
||||
// Define functions immediately and attach to window
|
||||
|
||||
function configurePlugin() {
|
||||
console.log('configurePlugin called');
|
||||
const status = document.getElementById('status');
|
||||
const configStatus = document.getElementById('configStatus');
|
||||
const fetcherStatus = document.getElementById('fetcherStatus');
|
||||
|
||||
status.innerHTML = 'Configuring plugin...';
|
||||
status.style.background = 'rgba(255, 255, 0, 0.3)'; // Yellow background
|
||||
|
||||
// Update top status to show configuring
|
||||
configStatus.innerHTML = '⏳ Configuring...';
|
||||
fetcherStatus.innerHTML = '⏳ Waiting...';
|
||||
|
||||
try {
|
||||
// Try to access the real plugin through Capacitor
|
||||
if (window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.DailyNotification) {
|
||||
plugin = window.Capacitor.Plugins.DailyNotification;
|
||||
isPluginAvailable = true;
|
||||
console.log('✅ Real DailyNotification plugin found!');
|
||||
updateStatus('success', '✅ Real DailyNotification plugin loaded successfully!');
|
||||
} else {
|
||||
// Fallback to mock for development
|
||||
console.log('⚠️ Real plugin not available, using mock for development');
|
||||
plugin = createMockPlugin();
|
||||
isPluginAvailable = false;
|
||||
updateStatus('warning', '⚠️ Using mock plugin (real plugin not available)');
|
||||
if (!window.DailyNotification) {
|
||||
status.innerHTML = 'DailyNotification plugin not available';
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
configStatus.innerHTML = '❌ Plugin unavailable';
|
||||
fetcherStatus.innerHTML = '❌ Plugin unavailable';
|
||||
return;
|
||||
}
|
||||
|
||||
// Configure plugin settings
|
||||
window.DailyNotification.configure({
|
||||
storage: 'tiered',
|
||||
ttlSeconds: 86400,
|
||||
prefetchLeadMinutes: 60,
|
||||
maxNotificationsPerDay: 3,
|
||||
retentionDays: 7
|
||||
})
|
||||
.then(() => {
|
||||
console.log('Plugin settings configured, now configuring native fetcher...');
|
||||
// Update top status
|
||||
configStatus.innerHTML = '✅ Configured';
|
||||
|
||||
// Configure native fetcher with demo credentials
|
||||
// Note: DemoNativeFetcher uses hardcoded mock data, so this is optional
|
||||
// but demonstrates the API. In production, this would be real credentials.
|
||||
return window.DailyNotification.configureNativeFetcher({
|
||||
apiBaseUrl: 'http://10.0.2.2:3000', // Android emulator → host localhost
|
||||
activeDid: 'did:ethr:0xDEMO1234567890', // Demo DID
|
||||
jwtSecret: 'demo-jwt-secret-for-development-testing'
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
// Update top status
|
||||
fetcherStatus.innerHTML = '✅ Configured';
|
||||
|
||||
// Update bottom status for user feedback
|
||||
status.innerHTML = 'Plugin configured successfully!';
|
||||
status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background
|
||||
})
|
||||
.catch(error => {
|
||||
// Update top status with error
|
||||
if (configStatus.innerHTML.includes('Configuring')) {
|
||||
configStatus.innerHTML = '❌ Failed';
|
||||
}
|
||||
if (fetcherStatus.innerHTML.includes('Waiting') || fetcherStatus.innerHTML.includes('Configuring')) {
|
||||
fetcherStatus.innerHTML = '❌ Failed';
|
||||
}
|
||||
|
||||
status.innerHTML = `Configuration failed: ${error.message}`;
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('❌ Plugin initialization failed:', error);
|
||||
updateStatus('error', `❌ Plugin initialization failed: ${error.message}`);
|
||||
configStatus.innerHTML = '❌ Error';
|
||||
fetcherStatus.innerHTML = '❌ Error';
|
||||
status.innerHTML = `Configuration failed: ${error.message}`;
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
}
|
||||
}
|
||||
|
||||
// Create mock plugin for development/testing
|
||||
function createMockPlugin() {
|
||||
return {
|
||||
configure: async (options) => {
|
||||
console.log('Mock configure called with:', options);
|
||||
return Promise.resolve();
|
||||
},
|
||||
getNotificationStatus: async () => {
|
||||
return Promise.resolve({
|
||||
isEnabled: true,
|
||||
isScheduled: true,
|
||||
lastNotificationTime: Date.now() - 86400000,
|
||||
nextNotificationTime: Date.now() + 3600000,
|
||||
pending: 1,
|
||||
settings: { url: 'https://api.example.com/content', time: '09:00' },
|
||||
error: null
|
||||
});
|
||||
},
|
||||
checkPermissions: async () => {
|
||||
return Promise.resolve({
|
||||
notifications: 'granted',
|
||||
backgroundRefresh: 'granted',
|
||||
alert: true,
|
||||
badge: true,
|
||||
sound: true
|
||||
});
|
||||
},
|
||||
requestPermissions: async () => {
|
||||
return Promise.resolve({
|
||||
notifications: 'granted',
|
||||
backgroundRefresh: 'granted',
|
||||
alert: true,
|
||||
badge: true,
|
||||
sound: true
|
||||
});
|
||||
},
|
||||
scheduleDailyNotification: async (options) => {
|
||||
console.log('Mock scheduleDailyNotification called with:', options);
|
||||
return Promise.resolve();
|
||||
},
|
||||
cancelAllNotifications: async () => {
|
||||
console.log('Mock cancelAllNotifications called');
|
||||
return Promise.resolve();
|
||||
},
|
||||
getLastNotification: async () => {
|
||||
return Promise.resolve({
|
||||
id: 'mock-123',
|
||||
title: 'Mock Notification',
|
||||
body: 'This is a mock notification',
|
||||
timestamp: Date.now() - 3600000,
|
||||
url: 'https://example.com'
|
||||
});
|
||||
},
|
||||
getBatteryStatus: async () => {
|
||||
return Promise.resolve({
|
||||
level: 85,
|
||||
isCharging: false,
|
||||
powerState: 1,
|
||||
isOptimizationExempt: false
|
||||
});
|
||||
},
|
||||
getExactAlarmStatus: async () => {
|
||||
return Promise.resolve({
|
||||
supported: true,
|
||||
enabled: true,
|
||||
canSchedule: true,
|
||||
fallbackWindow: '±15 minutes'
|
||||
});
|
||||
},
|
||||
requestExactAlarmPermission: async () => {
|
||||
console.log('Mock requestExactAlarmPermission called');
|
||||
return Promise.resolve();
|
||||
},
|
||||
openExactAlarmSettings: async () => {
|
||||
console.log('Mock openExactAlarmSettings called');
|
||||
return Promise.resolve();
|
||||
},
|
||||
requestBatteryOptimizationExemption: async () => {
|
||||
console.log('Mock requestBatteryOptimizationExemption called');
|
||||
return Promise.resolve();
|
||||
},
|
||||
getRebootRecoveryStatus: async () => {
|
||||
return Promise.resolve({
|
||||
inProgress: false,
|
||||
lastRecoveryTime: Date.now() - 86400000,
|
||||
timeSinceLastRecovery: 86400000,
|
||||
recoveryNeeded: false
|
||||
});
|
||||
},
|
||||
getRollingWindowStats: async () => {
|
||||
return Promise.resolve({
|
||||
stats: 'Window: 7 days, Notifications: 5, Success rate: 100%',
|
||||
maintenanceNeeded: false,
|
||||
timeUntilNextMaintenance: 3600000
|
||||
});
|
||||
},
|
||||
maintainRollingWindow: async () => {
|
||||
console.log('Mock maintainRollingWindow called');
|
||||
return Promise.resolve();
|
||||
},
|
||||
getContentCache: async () => {
|
||||
return Promise.resolve({
|
||||
'cache-key-1': { content: 'Mock cached content', timestamp: Date.now() },
|
||||
'cache-key-2': { content: 'Another mock item', timestamp: Date.now() - 3600000 }
|
||||
});
|
||||
},
|
||||
clearContentCache: async () => {
|
||||
console.log('Mock clearContentCache called');
|
||||
return Promise.resolve();
|
||||
},
|
||||
getContentHistory: async () => {
|
||||
return Promise.resolve([
|
||||
{ id: '1', timestamp: Date.now() - 86400000, success: true, content: 'Mock content 1' },
|
||||
{ id: '2', timestamp: Date.now() - 172800000, success: true, content: 'Mock content 2' }
|
||||
]);
|
||||
},
|
||||
getDualScheduleStatus: async () => {
|
||||
return Promise.resolve({
|
||||
isActive: true,
|
||||
contentSchedule: { nextRun: Date.now() + 3600000, isEnabled: true },
|
||||
userSchedule: { nextRun: Date.now() + 7200000, isEnabled: true },
|
||||
lastContentFetch: Date.now() - 3600000,
|
||||
lastUserNotification: Date.now() - 7200000
|
||||
});
|
||||
|
||||
function loadPluginStatus() {
|
||||
console.log('loadPluginStatus called');
|
||||
const pluginStatusContent = document.getElementById('pluginStatusContent');
|
||||
const statusCard = document.getElementById('statusCard');
|
||||
|
||||
try {
|
||||
if (!window.DailyNotification) {
|
||||
pluginStatusContent.innerHTML = '❌ DailyNotification plugin not available';
|
||||
statusCard.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
return;
|
||||
}
|
||||
};
|
||||
window.DailyNotification.getNotificationStatus()
|
||||
.then(result => {
|
||||
const nextTime = result.nextNotificationTime ? new Date(result.nextNotificationTime).toLocaleString() : 'None scheduled';
|
||||
const hasSchedules = result.isEnabled || (result.pending && result.pending > 0);
|
||||
const statusIcon = hasSchedules ? '✅' : '⏸️';
|
||||
pluginStatusContent.innerHTML = `${statusIcon} Active Schedules: ${hasSchedules ? 'Yes' : 'No'}<br>
|
||||
📅 Next Notification: ${nextTime}<br>
|
||||
⏳ Pending: ${result.pending || 0}`;
|
||||
statusCard.style.background = hasSchedules ?
|
||||
'rgba(0, 255, 0, 0.15)' : 'rgba(255, 255, 255, 0.1)'; // Green if active, light gray if none
|
||||
})
|
||||
.catch(error => {
|
||||
pluginStatusContent.innerHTML = `⚠️ Status check failed: ${error.message}`;
|
||||
statusCard.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
});
|
||||
} catch (error) {
|
||||
pluginStatusContent.innerHTML = `⚠️ Status check failed: ${error.message}`;
|
||||
statusCard.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
}
|
||||
}
|
||||
|
||||
// Utility function to update status display
|
||||
function updateStatus(type, message) {
|
||||
const statusEl = document.getElementById('status');
|
||||
statusEl.className = `status ${type}`;
|
||||
statusEl.textContent = message;
|
||||
console.log(`[${type.toUpperCase()}] ${message}`);
|
||||
}
|
||||
|
||||
// Plugin availability check
|
||||
async function checkPluginAvailability() {
|
||||
updateStatus('info', '🔍 Checking plugin availability...');
|
||||
|
||||
// Notification test functions
|
||||
function testNotification() {
|
||||
console.log('testNotification called');
|
||||
|
||||
// Quick sanity check - test plugin availability
|
||||
if (window.Capacitor && window.Capacitor.isPluginAvailable) {
|
||||
const isAvailable = window.Capacitor.isPluginAvailable('DailyNotification');
|
||||
console.log('is plugin available?', isAvailable);
|
||||
}
|
||||
|
||||
const status = document.getElementById('status');
|
||||
status.innerHTML = 'Testing plugin connection...';
|
||||
status.style.background = 'rgba(255, 255, 0, 0.3)'; // Yellow background
|
||||
|
||||
try {
|
||||
if (plugin) {
|
||||
updateStatus('success', `✅ Plugin available: ${isPluginAvailable ? 'Real plugin' : 'Mock plugin'}`);
|
||||
} else {
|
||||
updateStatus('error', '❌ Plugin not available');
|
||||
if (!window.DailyNotification) {
|
||||
status.innerHTML = 'DailyNotification plugin not available';
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Availability check failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Get notification status
|
||||
async function getNotificationStatus() {
|
||||
updateStatus('info', '📊 Getting notification status...');
|
||||
try {
|
||||
const status = await plugin.getNotificationStatus();
|
||||
updateStatus('success', `📊 Status: ${JSON.stringify(status, null, 2)}`);
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Status check failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Check permissions
|
||||
async function checkPermissions() {
|
||||
updateStatus('info', '🔐 Checking permissions...');
|
||||
try {
|
||||
const permissions = await plugin.checkPermissions();
|
||||
updateStatus('success', `🔐 Permissions: ${JSON.stringify(permissions, null, 2)}`);
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Permission check failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Request permissions
|
||||
async function requestPermissions() {
|
||||
updateStatus('info', '🔐 Requesting permissions...');
|
||||
try {
|
||||
const result = await plugin.requestPermissions();
|
||||
updateStatus('success', `🔐 Permission result: ${JSON.stringify(result, null, 2)}`);
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Permission request failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Get battery status
|
||||
async function getBatteryStatus() {
|
||||
updateStatus('info', '🔋 Getting battery status...');
|
||||
try {
|
||||
const battery = await plugin.getBatteryStatus();
|
||||
updateStatus('success', `🔋 Battery: ${JSON.stringify(battery, null, 2)}`);
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Battery check failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule notification
|
||||
async function scheduleNotification() {
|
||||
updateStatus('info', '⏰ Scheduling notification...');
|
||||
try {
|
||||
const timeInput = document.getElementById('notificationTime').value;
|
||||
const [hours, minutes] = timeInput.split(':');
|
||||
|
||||
// Test the notification method directly
|
||||
console.log('Testing notification scheduling...');
|
||||
const now = new Date();
|
||||
const scheduledTime = new Date();
|
||||
scheduledTime.setHours(parseInt(hours), parseInt(minutes), 0, 0);
|
||||
|
||||
// If scheduled time is in the past, schedule for tomorrow
|
||||
if (scheduledTime <= now) {
|
||||
scheduledTime.setDate(scheduledTime.getDate() + 1);
|
||||
}
|
||||
|
||||
// Calculate prefetch time (2 minutes before notification)
|
||||
const prefetchTime = new Date(scheduledTime.getTime() - 120000); // 2 minutes
|
||||
const prefetchTimeReadable = prefetchTime.toLocaleTimeString();
|
||||
const notificationTimeReadable = scheduledTime.toLocaleTimeString();
|
||||
const notificationTime = new Date(now.getTime() + 240000); // 4 minutes from now
|
||||
const prefetchTime = new Date(now.getTime() + 120000); // 2 minutes from now (2 min before notification)
|
||||
const notificationTimeString = notificationTime.getHours().toString().padStart(2, '0') + ':' +
|
||||
notificationTime.getMinutes().toString().padStart(2, '0');
|
||||
const prefetchTimeString = prefetchTime.getHours().toString().padStart(2, '0') + ':' +
|
||||
prefetchTime.getMinutes().toString().padStart(2, '0');
|
||||
const notificationTimeString = scheduledTime.getHours().toString().padStart(2, '0') + ':' +
|
||||
scheduledTime.getMinutes().toString().padStart(2, '0');
|
||||
|
||||
const options = {
|
||||
url: document.getElementById('notificationUrl').value,
|
||||
time: timeInput,
|
||||
title: document.getElementById('notificationTitle').value,
|
||||
body: document.getElementById('notificationBody').value,
|
||||
window.DailyNotification.scheduleDailyNotification({
|
||||
time: notificationTimeString,
|
||||
title: 'Test Notification',
|
||||
body: 'This is a test notification from the DailyNotification plugin!',
|
||||
sound: true,
|
||||
priority: 'high'
|
||||
};
|
||||
await plugin.scheduleDailyNotification(options);
|
||||
updateStatus('success', `✅ Notification scheduled!<br>` +
|
||||
`📥 Prefetch: ${prefetchTimeReadable} (${prefetchTimeString})<br>` +
|
||||
`🔔 Notification: ${notificationTimeReadable} (${notificationTimeString})`);
|
||||
})
|
||||
.then(() => {
|
||||
const prefetchTimeReadable = prefetchTime.toLocaleTimeString();
|
||||
const notificationTimeReadable = notificationTime.toLocaleTimeString();
|
||||
status.innerHTML = '✅ Notification scheduled!<br>' +
|
||||
'📥 Prefetch: ' + prefetchTimeReadable + ' (' + prefetchTimeString + ')<br>' +
|
||||
'🔔 Notification: ' + notificationTimeReadable + ' (' + notificationTimeString + ')';
|
||||
status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background
|
||||
// Refresh plugin status display
|
||||
setTimeout(() => loadPluginStatus(), 500);
|
||||
})
|
||||
.catch(error => {
|
||||
// Check if this is an exact alarm permission error
|
||||
if (error.code === 'EXACT_ALARM_PERMISSION_REQUIRED' ||
|
||||
error.message.includes('Exact alarm permission') ||
|
||||
error.message.includes('Alarms & reminders')) {
|
||||
status.innerHTML = '⚠️ Exact Alarm Permission Required<br><br>' +
|
||||
'Settings opened automatically.<br>' +
|
||||
'Please enable "Allow exact alarms" and return to try again.';
|
||||
status.style.background = 'rgba(255, 165, 0, 0.3)'; // Orange background
|
||||
} else {
|
||||
status.innerHTML = `❌ Notification failed: ${error.message}`;
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Scheduling failed: ${error.message}`);
|
||||
status.innerHTML = `Notification test failed: ${error.message}`;
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel all notifications
|
||||
async function cancelAllNotifications() {
|
||||
updateStatus('info', '❌ Cancelling all notifications...');
|
||||
|
||||
|
||||
// Permission management functions
|
||||
function requestPermissions() {
|
||||
console.log('requestPermissions called');
|
||||
const status = document.getElementById('status');
|
||||
status.innerHTML = 'Requesting permissions...';
|
||||
status.style.background = 'rgba(255, 255, 0, 0.3)'; // Yellow background
|
||||
|
||||
try {
|
||||
await plugin.cancelAllNotifications();
|
||||
updateStatus('success', '❌ All notifications cancelled');
|
||||
if (!window.DailyNotification) {
|
||||
status.innerHTML = 'DailyNotification plugin not available';
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
return;
|
||||
}
|
||||
|
||||
window.DailyNotification.requestNotificationPermissions()
|
||||
.then(() => {
|
||||
status.innerHTML = 'Permission request completed! Check your device settings if needed.';
|
||||
status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background
|
||||
|
||||
// Refresh permission and channel status display after request
|
||||
setTimeout(() => {
|
||||
loadPermissionStatus();
|
||||
loadChannelStatus();
|
||||
}, 1000);
|
||||
})
|
||||
.catch(error => {
|
||||
status.innerHTML = `Permission request failed: ${error.message}`;
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
});
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Cancel failed: ${error.message}`);
|
||||
status.innerHTML = `Permission request failed: ${error.message}`;
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
}
|
||||
}
|
||||
|
||||
// Get last notification
|
||||
async function getLastNotification() {
|
||||
updateStatus('info', '📱 Getting last notification...');
|
||||
|
||||
function loadChannelStatus() {
|
||||
const channelStatus = document.getElementById('channelStatus');
|
||||
|
||||
try {
|
||||
const notification = await plugin.getLastNotification();
|
||||
updateStatus('success', `📱 Last notification: ${JSON.stringify(notification, null, 2)}`);
|
||||
if (!window.DailyNotification) {
|
||||
channelStatus.innerHTML = '❌ Plugin unavailable';
|
||||
return;
|
||||
}
|
||||
|
||||
window.DailyNotification.isChannelEnabled()
|
||||
.then(result => {
|
||||
const importanceText = getImportanceText(result.importance);
|
||||
if (result.enabled) {
|
||||
channelStatus.innerHTML = `✅ Enabled (${importanceText})`;
|
||||
} else {
|
||||
channelStatus.innerHTML = `❌ Disabled (${importanceText})`;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
channelStatus.innerHTML = '⚠️ Error';
|
||||
});
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Get last notification failed: ${error.message}`);
|
||||
channelStatus.innerHTML = '⚠️ Error';
|
||||
}
|
||||
}
|
||||
|
||||
// Configure plugin
|
||||
async function configurePlugin() {
|
||||
updateStatus('info', '⚙️ Configuring plugin...');
|
||||
|
||||
function checkComprehensiveStatus() {
|
||||
const status = document.getElementById('status');
|
||||
status.innerHTML = 'Checking comprehensive status...';
|
||||
status.style.background = 'rgba(255, 255, 0, 0.3)'; // Yellow background
|
||||
|
||||
try {
|
||||
const config = {
|
||||
fetchUrl: document.getElementById('configUrl').value,
|
||||
scheduleTime: document.getElementById('configTime').value,
|
||||
retryCount: parseInt(document.getElementById('configRetryCount').value),
|
||||
enableNotifications: true,
|
||||
offlineFallback: true
|
||||
};
|
||||
await plugin.configure(config);
|
||||
updateStatus('success', `⚙️ Plugin configured: ${JSON.stringify(config, null, 2)}`);
|
||||
if (!window.DailyNotification) {
|
||||
status.innerHTML = 'DailyNotification plugin not available';
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
return;
|
||||
}
|
||||
|
||||
window.DailyNotification.checkStatus()
|
||||
.then(result => {
|
||||
const canSchedule = result.canScheduleNow;
|
||||
const issues = [];
|
||||
|
||||
if (!result.postNotificationsGranted) {
|
||||
issues.push('POST_NOTIFICATIONS permission');
|
||||
}
|
||||
if (!result.channelEnabled) {
|
||||
issues.push('notification channel disabled');
|
||||
}
|
||||
if (!result.exactAlarmsGranted) {
|
||||
issues.push('exact alarm permission');
|
||||
}
|
||||
|
||||
let statusText = `Status: ${canSchedule ? 'Ready to schedule' : 'Issues found'}`;
|
||||
if (issues.length > 0) {
|
||||
statusText += `\nIssues: ${issues.join(', ')}`;
|
||||
}
|
||||
|
||||
statusText += `\nChannel: ${getImportanceText(result.channelImportance)}`;
|
||||
statusText += `\nChannel ID: ${result.channelId}`;
|
||||
|
||||
status.innerHTML = statusText;
|
||||
status.style.background = canSchedule ? 'rgba(0, 255, 0, 0.3)' : 'rgba(255, 0, 0, 0.3)';
|
||||
})
|
||||
.catch(error => {
|
||||
status.innerHTML = `Status check failed: ${error.message}`;
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
});
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Configuration failed: ${error.message}`);
|
||||
status.innerHTML = `Status check failed: ${error.message}`;
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
}
|
||||
}
|
||||
|
||||
function getImportanceText(importance) {
|
||||
switch (importance) {
|
||||
case 0: return 'None (blocked)';
|
||||
case 1: return 'Min';
|
||||
case 2: return 'Low';
|
||||
case 3: return 'Default';
|
||||
case 4: return 'High';
|
||||
case 5: return 'Max';
|
||||
default: return `Unknown (${importance})`;
|
||||
}
|
||||
}
|
||||
|
||||
// Attach to window object
|
||||
window.configurePlugin = configurePlugin;
|
||||
window.testNotification = testNotification;
|
||||
window.requestPermissions = requestPermissions;
|
||||
window.checkComprehensiveStatus = checkComprehensiveStatus;
|
||||
|
||||
// Update settings
|
||||
async function updateSettings() {
|
||||
updateStatus('info', '⚙️ Updating settings...');
|
||||
function loadPermissionStatus() {
|
||||
const notificationPermStatus = document.getElementById('notificationPermStatus');
|
||||
const exactAlarmPermStatus = document.getElementById('exactAlarmPermStatus');
|
||||
|
||||
try {
|
||||
const settings = {
|
||||
url: document.getElementById('configUrl').value,
|
||||
time: document.getElementById('configTime').value,
|
||||
retryCount: parseInt(document.getElementById('configRetryCount').value),
|
||||
sound: true,
|
||||
priority: 'high'
|
||||
};
|
||||
await plugin.updateSettings(settings);
|
||||
updateStatus('success', `⚙️ Settings updated: ${JSON.stringify(settings, null, 2)}`);
|
||||
if (!window.DailyNotification) {
|
||||
notificationPermStatus.innerHTML = '❌ Plugin unavailable';
|
||||
exactAlarmPermStatus.innerHTML = '❌ Plugin unavailable';
|
||||
return;
|
||||
}
|
||||
|
||||
window.DailyNotification.checkPermissionStatus()
|
||||
.then(result => {
|
||||
notificationPermStatus.innerHTML = result.notificationsEnabled ? '✅ Granted' : '❌ Not granted';
|
||||
exactAlarmPermStatus.innerHTML = result.exactAlarmEnabled ? '✅ Granted' : '❌ Not granted';
|
||||
})
|
||||
.catch(error => {
|
||||
notificationPermStatus.innerHTML = '⚠️ Error';
|
||||
exactAlarmPermStatus.innerHTML = '⚠️ Error';
|
||||
});
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Settings update failed: ${error.message}`);
|
||||
notificationPermStatus.innerHTML = '⚠️ Error';
|
||||
exactAlarmPermStatus.innerHTML = '⚠️ Error';
|
||||
}
|
||||
}
|
||||
|
||||
// Get exact alarm status
|
||||
async function getExactAlarmStatus() {
|
||||
updateStatus('info', '⏰ Getting exact alarm status...');
|
||||
try {
|
||||
const status = await plugin.getExactAlarmStatus();
|
||||
updateStatus('success', `⏰ Exact alarm status: ${JSON.stringify(status, null, 2)}`);
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Exact alarm check failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
// Load plugin status automatically on page load
|
||||
window.addEventListener('load', () => {
|
||||
console.log('Page loaded, loading plugin status...');
|
||||
// Small delay to ensure Capacitor is ready
|
||||
setTimeout(() => {
|
||||
loadPluginStatus();
|
||||
loadPermissionStatus();
|
||||
loadChannelStatus();
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// Request exact alarm permission
|
||||
async function requestExactAlarmPermission() {
|
||||
updateStatus('info', '⏰ Requesting exact alarm permission...');
|
||||
try {
|
||||
await plugin.requestExactAlarmPermission();
|
||||
updateStatus('success', '⏰ Exact alarm permission requested');
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Exact alarm permission request failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Open exact alarm settings
|
||||
async function openExactAlarmSettings() {
|
||||
updateStatus('info', '⚙️ Opening exact alarm settings...');
|
||||
try {
|
||||
await plugin.openExactAlarmSettings();
|
||||
updateStatus('success', '⚙️ Exact alarm settings opened');
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Open settings failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Request battery optimization exemption
|
||||
async function requestBatteryOptimizationExemption() {
|
||||
updateStatus('info', '🔋 Requesting battery optimization exemption...');
|
||||
try {
|
||||
await plugin.requestBatteryOptimizationExemption();
|
||||
updateStatus('success', '🔋 Battery optimization exemption requested');
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Battery exemption request failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Get reboot recovery status
|
||||
async function getRebootRecoveryStatus() {
|
||||
updateStatus('info', '🔄 Getting reboot recovery status...');
|
||||
try {
|
||||
const status = await plugin.getRebootRecoveryStatus();
|
||||
updateStatus('success', `🔄 Reboot recovery status: ${JSON.stringify(status, null, 2)}`);
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Reboot recovery check failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Get rolling window stats
|
||||
async function getRollingWindowStats() {
|
||||
updateStatus('info', '📊 Getting rolling window stats...');
|
||||
try {
|
||||
const stats = await plugin.getRollingWindowStats();
|
||||
updateStatus('success', `📊 Rolling window stats: ${JSON.stringify(stats, null, 2)}`);
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Rolling window stats failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Maintain rolling window
|
||||
async function maintainRollingWindow() {
|
||||
updateStatus('info', '🔧 Maintaining rolling window...');
|
||||
try {
|
||||
await plugin.maintainRollingWindow();
|
||||
updateStatus('success', '🔧 Rolling window maintenance completed');
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Rolling window maintenance failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Get content cache
|
||||
async function getContentCache() {
|
||||
updateStatus('info', '💾 Getting content cache...');
|
||||
try {
|
||||
const cache = await plugin.getContentCache();
|
||||
updateStatus('success', `💾 Content cache: ${JSON.stringify(cache, null, 2)}`);
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Content cache check failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear content cache
|
||||
async function clearContentCache() {
|
||||
updateStatus('info', '🗑️ Clearing content cache...');
|
||||
try {
|
||||
await plugin.clearContentCache();
|
||||
updateStatus('success', '🗑️ Content cache cleared');
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Clear cache failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Get content history
|
||||
async function getContentHistory() {
|
||||
updateStatus('info', '📚 Getting content history...');
|
||||
try {
|
||||
const history = await plugin.getContentHistory();
|
||||
updateStatus('success', `📚 Content history: ${JSON.stringify(history, null, 2)}`);
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Content history check failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Get dual schedule status
|
||||
async function getDualScheduleStatus() {
|
||||
updateStatus('info', '🔄 Getting dual schedule status...');
|
||||
try {
|
||||
const status = await plugin.getDualScheduleStatus();
|
||||
updateStatus('success', `🔄 Dual schedule status: ${JSON.stringify(status, null, 2)}`);
|
||||
} catch (error) {
|
||||
updateStatus('error', `❌ Dual schedule check failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('🔔 DailyNotification Plugin Test Interface Loaded Successfully!');
|
||||
console.log('Functions attached to window:', {
|
||||
configurePlugin: typeof window.configurePlugin,
|
||||
testNotification: typeof window.testNotification
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user