fix: resolve TypeScript and ESLint errors, fix Android build
TypeScript Import Fixes: - Use type-only imports for interfaces in all lib files - Fix import statements in schema-validation.ts, error-handling.ts, typed-plugin.ts, diagnostics-export.ts, StatusView.vue ESLint Error Fixes: - Replace all 'any' types with proper type annotations - Use 'unknown' for unvalidated inputs with proper type guards - Use Record<string, unknown> for object properties - Add proper type casting for Performance API and Navigator properties - Fix deprecated Vue filter by replacing type assertion with function StatusCard Component Fixes: - Fix prop type mismatch by changing template structure - Add getStatusType() function for type-safe status conversion - Add getStatusDescription() function for descriptive text - Update HomeView.vue to use multiple StatusCard components in grid Android Build Fix: - Fix capacitor.settings.gradle plugin path from 'android' to 'android/plugin' - Resolve Gradle dependency resolution issue - Enable successful Android APK generation Key improvements: - Full type safety with proper TypeScript interfaces - ESLint compliance with no remaining errors - Successful web and Android builds - Better error handling with typed error objects - Improved developer experience with IntelliSense support
This commit is contained in:
@@ -227,12 +227,14 @@ android/
|
|||||||
### Important Distinctions
|
### Important Distinctions
|
||||||
|
|
||||||
#### Plugin Module (`android/plugin/`)
|
#### Plugin Module (`android/plugin/`)
|
||||||
|
|
||||||
- **Purpose**: Contains the actual plugin code
|
- **Purpose**: Contains the actual plugin code
|
||||||
- **No MainActivity** - This is a library, not an app
|
- **No MainActivity** - This is a library, not an app
|
||||||
- **No UI Components** - Plugins provide functionality to host apps
|
- **No UI Components** - Plugins provide functionality to host apps
|
||||||
- **Output**: AAR library files
|
- **Output**: AAR library files
|
||||||
|
|
||||||
#### Test App Module (`android/app/`)
|
#### Test App Module (`android/app/`)
|
||||||
|
|
||||||
- **Purpose**: Test application for the plugin
|
- **Purpose**: Test application for the plugin
|
||||||
- **Has MainActivity** - Full Capacitor app with BridgeActivity
|
- **Has MainActivity** - Full Capacitor app with BridgeActivity
|
||||||
- **Has UI Components** - HTML/JS interface for testing
|
- **Has UI Components** - HTML/JS interface for testing
|
||||||
@@ -392,6 +394,7 @@ npx cap run ios
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Test App Features:**
|
**Test App Features:**
|
||||||
|
|
||||||
- Interactive plugin testing interface
|
- Interactive plugin testing interface
|
||||||
- Plugin diagnostics and status checking
|
- Plugin diagnostics and status checking
|
||||||
- Notification scheduling and management
|
- Notification scheduling and management
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
PermissionStatus,
|
type PermissionStatus,
|
||||||
NotificationStatus,
|
type NotificationStatus,
|
||||||
ExactAlarmStatus
|
type ExactAlarmStatus
|
||||||
} from './bridge'
|
} from './bridge'
|
||||||
|
|
||||||
export interface ComprehensiveDiagnostics {
|
export interface ComprehensiveDiagnostics {
|
||||||
@@ -179,13 +179,15 @@ export class DiagnosticsExporter {
|
|||||||
* Collect network information
|
* Collect network information
|
||||||
*/
|
*/
|
||||||
private collectNetworkInfo() {
|
private collectNetworkInfo() {
|
||||||
const connection = (navigator as any).connection || (navigator as any).mozConnection || (navigator as any).webkitConnection
|
const connection = (navigator as Navigator & { connection?: unknown }).connection ||
|
||||||
|
(navigator as Navigator & { mozConnection?: unknown }).mozConnection ||
|
||||||
|
(navigator as Navigator & { webkitConnection?: unknown }).webkitConnection
|
||||||
|
|
||||||
return {
|
return {
|
||||||
connectionType: connection?.type || 'unknown',
|
connectionType: (connection as { type?: string })?.type || 'unknown',
|
||||||
effectiveType: connection?.effectiveType,
|
effectiveType: (connection as { effectiveType?: string })?.effectiveType,
|
||||||
downlink: connection?.downlink,
|
downlink: (connection as { downlink?: number })?.downlink,
|
||||||
rtt: connection?.rtt
|
rtt: (connection as { rtt?: number })?.rtt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +208,7 @@ export class DiagnosticsExporter {
|
|||||||
*/
|
*/
|
||||||
private isStorageAvailable(type: string): boolean {
|
private isStorageAvailable(type: string): boolean {
|
||||||
try {
|
try {
|
||||||
const storage = (window as any)[type]
|
const storage = (window as unknown as Record<string, unknown>)[type]
|
||||||
if (!storage) return false
|
if (!storage) return false
|
||||||
|
|
||||||
if (type === 'indexedDB') {
|
if (type === 'indexedDB') {
|
||||||
@@ -219,8 +221,8 @@ export class DiagnosticsExporter {
|
|||||||
|
|
||||||
// Test localStorage/sessionStorage
|
// Test localStorage/sessionStorage
|
||||||
const test = '__storage_test__'
|
const test = '__storage_test__'
|
||||||
storage.setItem(test, test)
|
;(storage as { setItem: (key: string, value: string) => void }).setItem(test, test)
|
||||||
storage.removeItem(test)
|
;(storage as { removeItem: (key: string) => void }).removeItem(test)
|
||||||
return true
|
return true
|
||||||
} catch {
|
} catch {
|
||||||
return false
|
return false
|
||||||
@@ -231,7 +233,7 @@ export class DiagnosticsExporter {
|
|||||||
* Get memory usage (if available)
|
* Get memory usage (if available)
|
||||||
*/
|
*/
|
||||||
private getMemoryUsage(): number | undefined {
|
private getMemoryUsage(): number | undefined {
|
||||||
const memory = (performance as any).memory
|
const memory = (performance as Performance & { memory?: { usedJSHeapSize: number } }).memory
|
||||||
return memory ? memory.usedJSHeapSize : undefined
|
return memory ? memory.usedJSHeapSize : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,15 +8,17 @@
|
|||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ErrorCode, ErrorInfo } from './bridge'
|
import { ErrorCode, type ErrorInfo } from './bridge'
|
||||||
|
|
||||||
export class ErrorHandler {
|
export class ErrorHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map native error to canonical error
|
* Map native error to canonical error
|
||||||
*/
|
*/
|
||||||
mapNativeError(error: any): ErrorInfo {
|
mapNativeError(error: unknown): ErrorInfo {
|
||||||
const errorMessage = error?.message || error?.toString() || 'Unknown error'
|
const errorMessage = (error as { message?: string })?.message ||
|
||||||
|
(error as { toString?: () => string })?.toString?.() ||
|
||||||
|
'Unknown error'
|
||||||
|
|
||||||
// Map common error patterns
|
// Map common error patterns
|
||||||
if (errorMessage.includes('Permission denied')) {
|
if (errorMessage.includes('Permission denied')) {
|
||||||
@@ -123,18 +125,18 @@ export class ErrorHandler {
|
|||||||
/**
|
/**
|
||||||
* Log error with context
|
* Log error with context
|
||||||
*/
|
*/
|
||||||
logError(error: any, context: string = 'DailyNotification') {
|
logError(error: unknown, context: string = 'DailyNotification') {
|
||||||
console.error(`[${context}] Error:`, error)
|
console.error(`[${context}] Error:`, error)
|
||||||
|
|
||||||
if (error?.stack) {
|
if ((error as { stack?: string })?.stack) {
|
||||||
console.error(`[${context}] Stack:`, error.stack)
|
console.error(`[${context}] Stack:`, (error as { stack: string }).stack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle plugin method error
|
* Handle plugin method error
|
||||||
*/
|
*/
|
||||||
handlePluginError(error: any, method: string): ErrorInfo {
|
handlePluginError(error: unknown, method: string): ErrorInfo {
|
||||||
this.logError(error, `Plugin.${method}`)
|
this.logError(error, `Plugin.${method}`)
|
||||||
return this.mapNativeError(error)
|
return this.mapNativeError(error)
|
||||||
}
|
}
|
||||||
@@ -144,7 +146,7 @@ export class ErrorHandler {
|
|||||||
export const errorHandler = new ErrorHandler()
|
export const errorHandler = new ErrorHandler()
|
||||||
|
|
||||||
// Utility functions
|
// Utility functions
|
||||||
export function mapNativeError(error: any): ErrorInfo {
|
export function mapNativeError(error: unknown): ErrorInfo {
|
||||||
return errorHandler.mapNativeError(error)
|
return errorHandler.mapNativeError(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,10 +154,10 @@ export function createUserMessage(error: ErrorInfo): string {
|
|||||||
return errorHandler.createUserMessage(error)
|
return errorHandler.createUserMessage(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logError(error: any, context?: string): void {
|
export function logError(error: unknown, context?: string): void {
|
||||||
errorHandler.logError(error, context)
|
errorHandler.logError(error, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handlePluginError(error: any, method: string): ErrorInfo {
|
export function handlePluginError(error: unknown, method: string): ErrorInfo {
|
||||||
return errorHandler.handlePluginError(error, method)
|
return errorHandler.handlePluginError(error, method)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ScheduleRequest,
|
type ValidationResult,
|
||||||
ValidationResult,
|
|
||||||
ErrorCode,
|
ErrorCode,
|
||||||
PriorityType,
|
type PriorityType,
|
||||||
PermissionType
|
type PermissionType
|
||||||
} from './bridge'
|
} from './bridge'
|
||||||
|
|
||||||
export class SchemaValidator {
|
export class SchemaValidator {
|
||||||
@@ -21,37 +20,48 @@ export class SchemaValidator {
|
|||||||
/**
|
/**
|
||||||
* Validate schedule request input
|
* Validate schedule request input
|
||||||
*/
|
*/
|
||||||
validateScheduleRequest(request: any): ValidationResult {
|
validateScheduleRequest(request: unknown): ValidationResult {
|
||||||
const errors: string[] = []
|
const errors: string[] = []
|
||||||
|
|
||||||
|
// Type guard: ensure request is an object
|
||||||
|
if (!request || typeof request !== 'object') {
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
errors: ['Request must be an object'],
|
||||||
|
message: 'Request must be an object'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const req = request as Record<string, unknown>
|
||||||
|
|
||||||
// Validate time format (HH:mm)
|
// Validate time format (HH:mm)
|
||||||
if (!this.isValidTimeFormat(request.time)) {
|
if (!this.isValidTimeFormat(req.time as string)) {
|
||||||
errors.push('Time must be in HH:mm format (24-hour)')
|
errors.push('Time must be in HH:mm format (24-hour)')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate title length (enforce exactly: title ≤ 100 chars)
|
// Validate title length (enforce exactly: title ≤ 100 chars)
|
||||||
if (request.title && request.title.length > 100) {
|
if (req.title && typeof req.title === 'string' && req.title.length > 100) {
|
||||||
errors.push('Title must be 100 characters or less')
|
errors.push('Title must be 100 characters or less')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate body length (enforce exactly: body ≤ 500 chars)
|
// Validate body length (enforce exactly: body ≤ 500 chars)
|
||||||
if (request.body && request.body.length > 500) {
|
if (req.body && typeof req.body === 'string' && req.body.length > 500) {
|
||||||
errors.push('Body must be 500 characters or less')
|
errors.push('Body must be 500 characters or less')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate boolean fields
|
// Validate boolean fields
|
||||||
if (typeof request.sound !== 'boolean') {
|
if (typeof req.sound !== 'boolean') {
|
||||||
errors.push('Sound must be a boolean')
|
errors.push('Sound must be a boolean')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate priority
|
// Validate priority
|
||||||
if (!this.isValidPriority(request.priority)) {
|
if (!this.isValidPriority(req.priority)) {
|
||||||
errors.push('Priority must be low, default, or high')
|
errors.push('Priority must be low, default, or high')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject unknown fields
|
// Reject unknown fields
|
||||||
const allowedFields = ['time', 'title', 'body', 'sound', 'priority']
|
const allowedFields = ['time', 'title', 'body', 'sound', 'priority']
|
||||||
const unknownFields = Object.keys(request).filter(key => !allowedFields.includes(key))
|
const unknownFields = Object.keys(req).filter(key => !allowedFields.includes(key))
|
||||||
if (unknownFields.length > 0) {
|
if (unknownFields.length > 0) {
|
||||||
errors.push(`Unknown fields: ${unknownFields.join(', ')}`)
|
errors.push(`Unknown fields: ${unknownFields.join(', ')}`)
|
||||||
}
|
}
|
||||||
@@ -66,14 +76,15 @@ export class SchemaValidator {
|
|||||||
/**
|
/**
|
||||||
* Validate permission status response
|
* Validate permission status response
|
||||||
*/
|
*/
|
||||||
validatePermissionStatus(status: any): ValidationResult {
|
validatePermissionStatus(status: unknown): ValidationResult {
|
||||||
const errors: string[] = []
|
const errors: string[] = []
|
||||||
|
const statusObj = status as Record<string, unknown>
|
||||||
|
|
||||||
if (!this.isValidPermissionType(status.notifications)) {
|
if (!this.isValidPermissionType(statusObj.notifications)) {
|
||||||
errors.push('Notifications permission must be granted or denied')
|
errors.push('Notifications permission must be granted or denied')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof status.notificationsEnabled !== 'boolean') {
|
if (typeof statusObj.notificationsEnabled !== 'boolean') {
|
||||||
errors.push('NotificationsEnabled must be a boolean')
|
errors.push('NotificationsEnabled must be a boolean')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,18 +98,19 @@ export class SchemaValidator {
|
|||||||
/**
|
/**
|
||||||
* Validate notification status response
|
* Validate notification status response
|
||||||
*/
|
*/
|
||||||
validateNotificationStatus(status: any): ValidationResult {
|
validateNotificationStatus(status: unknown): ValidationResult {
|
||||||
const errors: string[] = []
|
const errors: string[] = []
|
||||||
|
const statusObj = status as Record<string, unknown>
|
||||||
|
|
||||||
if (typeof status.isEnabled !== 'boolean') {
|
if (typeof statusObj.isEnabled !== 'boolean') {
|
||||||
errors.push('IsEnabled must be a boolean')
|
errors.push('IsEnabled must be a boolean')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof status.isScheduled !== 'boolean') {
|
if (typeof statusObj.isScheduled !== 'boolean') {
|
||||||
errors.push('IsScheduled must be a boolean')
|
errors.push('IsScheduled must be a boolean')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof status.pending !== 'boolean') {
|
if (typeof statusObj.pending !== 'boolean') {
|
||||||
errors.push('Pending must be a boolean')
|
errors.push('Pending must be a boolean')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,14 +124,15 @@ export class SchemaValidator {
|
|||||||
/**
|
/**
|
||||||
* Validate exact alarm status response
|
* Validate exact alarm status response
|
||||||
*/
|
*/
|
||||||
validateExactAlarmStatus(status: any): ValidationResult {
|
validateExactAlarmStatus(status: unknown): ValidationResult {
|
||||||
const errors: string[] = []
|
const errors: string[] = []
|
||||||
|
const statusObj = status as Record<string, unknown>
|
||||||
|
|
||||||
if (typeof status.enabled !== 'boolean') {
|
if (typeof statusObj.enabled !== 'boolean') {
|
||||||
errors.push('Enabled must be a boolean')
|
errors.push('Enabled must be a boolean')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof status.supported !== 'boolean') {
|
if (typeof statusObj.supported !== 'boolean') {
|
||||||
errors.push('Supported must be a boolean')
|
errors.push('Supported must be a boolean')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,15 +156,15 @@ export class SchemaValidator {
|
|||||||
/**
|
/**
|
||||||
* Check if priority is valid
|
* Check if priority is valid
|
||||||
*/
|
*/
|
||||||
private isValidPriority(priority: any): priority is PriorityType {
|
private isValidPriority(priority: unknown): priority is PriorityType {
|
||||||
return ['low', 'default', 'high'].includes(priority)
|
return typeof priority === 'string' && ['low', 'default', 'high'].includes(priority)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if permission type is valid
|
* Check if permission type is valid
|
||||||
*/
|
*/
|
||||||
private isValidPermissionType(permission: any): permission is PermissionType {
|
private isValidPermissionType(permission: unknown): permission is PermissionType {
|
||||||
return ['granted', 'denied'].includes(permission)
|
return typeof permission === 'string' && ['granted', 'denied'].includes(permission)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -171,7 +184,7 @@ export class SchemaValidator {
|
|||||||
/**
|
/**
|
||||||
* Create success response
|
* Create success response
|
||||||
*/
|
*/
|
||||||
createSuccessResponse(data?: any) {
|
createSuccessResponse(data?: Record<string, unknown>) {
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
...data
|
...data
|
||||||
@@ -183,18 +196,18 @@ export class SchemaValidator {
|
|||||||
export const schemaValidator = new SchemaValidator()
|
export const schemaValidator = new SchemaValidator()
|
||||||
|
|
||||||
// Utility functions
|
// Utility functions
|
||||||
export function validateScheduleRequest(request: any): ValidationResult {
|
export function validateScheduleRequest(request: unknown): ValidationResult {
|
||||||
return schemaValidator.validateScheduleRequest(request)
|
return schemaValidator.validateScheduleRequest(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function validatePermissionStatus(status: any): ValidationResult {
|
export function validatePermissionStatus(status: unknown): ValidationResult {
|
||||||
return schemaValidator.validatePermissionStatus(status)
|
return schemaValidator.validatePermissionStatus(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function validateNotificationStatus(status: any): ValidationResult {
|
export function validateNotificationStatus(status: unknown): ValidationResult {
|
||||||
return schemaValidator.validateNotificationStatus(status)
|
return schemaValidator.validateNotificationStatus(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function validateExactAlarmStatus(status: any): ValidationResult {
|
export function validateExactAlarmStatus(status: unknown): ValidationResult {
|
||||||
return schemaValidator.validateExactAlarmStatus(status)
|
return schemaValidator.validateExactAlarmStatus(status)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,23 +9,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DailyNotificationBridge,
|
type DailyNotificationBridge,
|
||||||
ScheduleRequest,
|
type ScheduleRequest,
|
||||||
ScheduleResponse,
|
type ScheduleResponse,
|
||||||
PermissionStatus,
|
type PermissionStatus,
|
||||||
NotificationStatus,
|
type NotificationStatus,
|
||||||
ExactAlarmStatus,
|
type ExactAlarmStatus,
|
||||||
PermissionResult,
|
type PermissionResult,
|
||||||
NotificationContent
|
type NotificationContent
|
||||||
} from './bridge'
|
} from './bridge'
|
||||||
|
|
||||||
import { validateScheduleRequest } from './schema-validation'
|
import { validateScheduleRequest } from './schema-validation'
|
||||||
import { handlePluginError, logError } from './error-handling'
|
import { handlePluginError, logError } from './error-handling'
|
||||||
|
|
||||||
export class TypedDailyNotificationPlugin implements DailyNotificationBridge {
|
export class TypedDailyNotificationPlugin implements DailyNotificationBridge {
|
||||||
private plugin: any
|
private plugin: unknown
|
||||||
|
|
||||||
constructor(plugin: any) {
|
constructor(plugin: unknown) {
|
||||||
this.plugin = plugin
|
this.plugin = plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ export class TypedDailyNotificationPlugin implements DailyNotificationBridge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Call native plugin
|
// Call native plugin
|
||||||
const result = await this.plugin.scheduleDailyNotification(request)
|
const result = await (this.plugin as { scheduleDailyNotification: (req: ScheduleRequest) => Promise<ScheduleResponse> }).scheduleDailyNotification(request)
|
||||||
|
|
||||||
// Validate response
|
// Validate response
|
||||||
if (result && typeof result.success === 'boolean') {
|
if (result && typeof result.success === 'boolean') {
|
||||||
@@ -75,7 +75,7 @@ export class TypedDailyNotificationPlugin implements DailyNotificationBridge {
|
|||||||
*/
|
*/
|
||||||
async checkPermissions(): Promise<PermissionStatus> {
|
async checkPermissions(): Promise<PermissionStatus> {
|
||||||
try {
|
try {
|
||||||
const result = await this.plugin.checkPermissions()
|
const result = await (this.plugin as { checkPermissions: () => Promise<PermissionStatus> }).checkPermissions()
|
||||||
|
|
||||||
// Ensure response has required fields
|
// Ensure response has required fields
|
||||||
return {
|
return {
|
||||||
@@ -97,7 +97,7 @@ export class TypedDailyNotificationPlugin implements DailyNotificationBridge {
|
|||||||
*/
|
*/
|
||||||
async getNotificationStatus(): Promise<NotificationStatus> {
|
async getNotificationStatus(): Promise<NotificationStatus> {
|
||||||
try {
|
try {
|
||||||
const result = await this.plugin.getNotificationStatus()
|
const result = await (this.plugin as { getNotificationStatus: () => Promise<NotificationStatus> }).getNotificationStatus()
|
||||||
|
|
||||||
// Ensure response has required fields
|
// Ensure response has required fields
|
||||||
return {
|
return {
|
||||||
@@ -125,7 +125,7 @@ export class TypedDailyNotificationPlugin implements DailyNotificationBridge {
|
|||||||
*/
|
*/
|
||||||
async getExactAlarmStatus(): Promise<ExactAlarmStatus> {
|
async getExactAlarmStatus(): Promise<ExactAlarmStatus> {
|
||||||
try {
|
try {
|
||||||
const result = await this.plugin.getExactAlarmStatus()
|
const result = await (this.plugin as { getExactAlarmStatus: () => Promise<ExactAlarmStatus> }).getExactAlarmStatus()
|
||||||
|
|
||||||
// Ensure response has required fields
|
// Ensure response has required fields
|
||||||
return {
|
return {
|
||||||
@@ -147,11 +147,11 @@ export class TypedDailyNotificationPlugin implements DailyNotificationBridge {
|
|||||||
*/
|
*/
|
||||||
async requestPermissions(): Promise<PermissionResult> {
|
async requestPermissions(): Promise<PermissionResult> {
|
||||||
try {
|
try {
|
||||||
const result = await this.plugin.requestPermissions()
|
const result = await (this.plugin as { requestPermissions: () => Promise<PermissionStatus> }).requestPermissions()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
granted: Boolean(result.granted),
|
granted: result.notifications === 'granted',
|
||||||
permissions: await this.checkPermissions()
|
permissions: result
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -171,7 +171,7 @@ export class TypedDailyNotificationPlugin implements DailyNotificationBridge {
|
|||||||
*/
|
*/
|
||||||
async openExactAlarmSettings(): Promise<void> {
|
async openExactAlarmSettings(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await this.plugin.openExactAlarmSettings()
|
await (this.plugin as { openExactAlarmSettings: () => Promise<void> }).openExactAlarmSettings()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError(error, 'openExactAlarmSettings')
|
logError(error, 'openExactAlarmSettings')
|
||||||
throw error
|
throw error
|
||||||
@@ -183,7 +183,7 @@ export class TypedDailyNotificationPlugin implements DailyNotificationBridge {
|
|||||||
*/
|
*/
|
||||||
async openChannelSettings(): Promise<void> {
|
async openChannelSettings(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await this.plugin.openChannelSettings()
|
await (this.plugin as { openChannelSettings: () => Promise<void> }).openChannelSettings()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError(error, 'openChannelSettings')
|
logError(error, 'openChannelSettings')
|
||||||
throw error
|
throw error
|
||||||
@@ -195,7 +195,7 @@ export class TypedDailyNotificationPlugin implements DailyNotificationBridge {
|
|||||||
*/
|
*/
|
||||||
async requestBatteryOptimizationExemption(): Promise<void> {
|
async requestBatteryOptimizationExemption(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await this.plugin.requestBatteryOptimizationExemption()
|
await (this.plugin as { requestBatteryOptimizationExemption: () => Promise<void> }).requestBatteryOptimizationExemption()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError(error, 'requestBatteryOptimizationExemption')
|
logError(error, 'requestBatteryOptimizationExemption')
|
||||||
throw error
|
throw error
|
||||||
@@ -207,7 +207,7 @@ export class TypedDailyNotificationPlugin implements DailyNotificationBridge {
|
|||||||
*/
|
*/
|
||||||
async cancelAllNotifications(): Promise<void> {
|
async cancelAllNotifications(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await this.plugin.cancelAllNotifications()
|
await (this.plugin as { cancelAllNotifications: () => Promise<void> }).cancelAllNotifications()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError(error, 'cancelAllNotifications')
|
logError(error, 'cancelAllNotifications')
|
||||||
throw error
|
throw error
|
||||||
@@ -219,7 +219,7 @@ export class TypedDailyNotificationPlugin implements DailyNotificationBridge {
|
|||||||
*/
|
*/
|
||||||
async getLastNotification(): Promise<NotificationContent | null> {
|
async getLastNotification(): Promise<NotificationContent | null> {
|
||||||
try {
|
try {
|
||||||
const result = await this.plugin.getLastNotification()
|
const result = await (this.plugin as { getLastNotification: () => Promise<NotificationContent | null> }).getLastNotification()
|
||||||
return result || null
|
return result || null
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError(error, 'getLastNotification')
|
logError(error, 'getLastNotification')
|
||||||
|
|||||||
@@ -77,7 +77,17 @@
|
|||||||
<!-- System Status -->
|
<!-- System Status -->
|
||||||
<div class="system-status">
|
<div class="system-status">
|
||||||
<h2 class="section-title">System Status</h2>
|
<h2 class="section-title">System Status</h2>
|
||||||
<StatusCard :status="systemStatus" @refresh="refreshSystemStatus" />
|
<div class="status-grid">
|
||||||
|
<StatusCard
|
||||||
|
v-for="item in systemStatus"
|
||||||
|
:key="item.label"
|
||||||
|
:title="item.label"
|
||||||
|
:status="getStatusType(item.status)"
|
||||||
|
:value="item.value"
|
||||||
|
:description="getStatusDescription(item.label)"
|
||||||
|
@refresh="refreshSystemStatus"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Diagnostic Actions -->
|
<!-- Diagnostic Actions -->
|
||||||
<div class="section">
|
<div class="section">
|
||||||
@@ -218,10 +228,10 @@ const checkSystemStatus = async (): Promise<void> => {
|
|||||||
console.log('📊 Plugin permissions:', permissions)
|
console.log('📊 Plugin permissions:', permissions)
|
||||||
console.log('📊 Permissions details:')
|
console.log('📊 Permissions details:')
|
||||||
console.log(' - notifications:', permissions.notifications)
|
console.log(' - notifications:', permissions.notifications)
|
||||||
console.log(' - notificationsEnabled:', (permissions as any).notificationsEnabled)
|
console.log(' - notificationsEnabled:', (permissions as unknown as Record<string, unknown>).notificationsEnabled)
|
||||||
console.log(' - exactAlarmEnabled:', (permissions as any).exactAlarmEnabled)
|
console.log(' - exactAlarmEnabled:', (permissions as unknown as Record<string, unknown>).exactAlarmEnabled)
|
||||||
console.log(' - wakeLockEnabled:', (permissions as any).wakeLockEnabled)
|
console.log(' - wakeLockEnabled:', (permissions as unknown as Record<string, unknown>).wakeLockEnabled)
|
||||||
console.log(' - allPermissionsGranted:', (permissions as any).allPermissionsGranted)
|
console.log(' - allPermissionsGranted:', (permissions as unknown as Record<string, unknown>).allPermissionsGranted)
|
||||||
console.log('📊 Exact alarm status:', exactAlarmStatus)
|
console.log('📊 Exact alarm status:', exactAlarmStatus)
|
||||||
|
|
||||||
// Map plugin response to app store format
|
// Map plugin response to app store format
|
||||||
@@ -302,6 +312,35 @@ const checkSystemStatus = async (): Promise<void> => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getStatusType = (status: string): 'success' | 'warning' | 'error' | 'info' => {
|
||||||
|
switch (status) {
|
||||||
|
case 'success':
|
||||||
|
case 'warning':
|
||||||
|
case 'error':
|
||||||
|
case 'info':
|
||||||
|
return status
|
||||||
|
default:
|
||||||
|
return 'info'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStatusDescription = (label: string): string => {
|
||||||
|
switch (label) {
|
||||||
|
case 'Platform':
|
||||||
|
return 'Current platform information'
|
||||||
|
case 'Plugin':
|
||||||
|
return 'DailyNotification plugin availability'
|
||||||
|
case 'Permissions':
|
||||||
|
return 'Notification permission status'
|
||||||
|
case 'Can Schedule':
|
||||||
|
return 'Ready to schedule notifications'
|
||||||
|
case 'Next Scheduled':
|
||||||
|
return 'Next scheduled notification time'
|
||||||
|
default:
|
||||||
|
return 'System status information'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const refreshSystemStatus = async (): Promise<void> => {
|
const refreshSystemStatus = async (): Promise<void> => {
|
||||||
console.log('🔄 CLICK: Refresh System Status')
|
console.log('🔄 CLICK: Refresh System Status')
|
||||||
await checkSystemStatus()
|
await checkSystemStatus()
|
||||||
|
|||||||
@@ -88,7 +88,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Vue, Component, toNative } from 'vue-facing-decorator'
|
import { Vue, Component, toNative } from 'vue-facing-decorator'
|
||||||
import StatusCard from '../components/cards/StatusCard.vue'
|
import StatusCard from '../components/cards/StatusCard.vue'
|
||||||
import { createTypedPlugin, type PermissionStatus, type NotificationStatus, type ExactAlarmStatus } from '../lib/typed-plugin'
|
import { createTypedPlugin } from '../lib/typed-plugin'
|
||||||
import { collectDiagnostics, copyDiagnosticsToClipboard, type ComprehensiveDiagnostics } from '../lib/diagnostics-export'
|
import { collectDiagnostics, copyDiagnosticsToClipboard, type ComprehensiveDiagnostics } from '../lib/diagnostics-export'
|
||||||
|
|
||||||
interface StatusItem {
|
interface StatusItem {
|
||||||
|
|||||||
Reference in New Issue
Block a user