@@ -48,6 +48,7 @@ async function initializeApplication() {
48
48
const apps = await loadApps ( ) ;
49
49
renderApps ( apps ) ;
50
50
setupCategoryFilter ( apps ) ;
51
+ startAppStatusChecker ( ) ;
51
52
} catch ( error ) {
52
53
console . error ( 'Application initialization failed:' , error ) ;
53
54
}
@@ -71,63 +72,121 @@ function renderApps(apps) {
71
72
72
73
apps . forEach ( app => {
73
74
const card = document . createElement ( 'div' ) ;
74
- card . className = `group bg-gradient-to-b from-white to-gray-50 dark:from-gray-700 dark:to-gray-800 rounded-xl shadow border hover:shadow-lg transition-all duration-300 dark:border-gray-700 cursor-pointer overflow-hidden` ;
75
+ card . className = `group bg-gradient-to-b from-white to-gray-50 dark:from-gray-700 dark:to-gray-800 rounded-xl shadow border hover:shadow-lg transition-all duration-300 dark:border-gray-700 overflow-hidden cursor-pointer` ;
76
+ card . id = `card-${ app . script } ` ;
75
77
76
78
card . innerHTML = `
77
79
<div class="relative h-full flex flex-col">
78
80
<div class="w-full h-32 bg-${ app . color } -100 dark:bg-${ app . color } -900 rounded-t-lg flex items-center justify-center transition-all duration-300 group-hover:opacity-90">
79
81
<i class="fas ${ app . icon } text-4xl text-${ app . color } -600 dark:text-${ app . color } -300"></i>
80
82
</div>
81
83
<div class="p-4 flex-1 flex flex-col">
82
- <h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-1">${ app . title } </h3>
84
+ <div class="flex items-center justify-between">
85
+ <h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-1">${ app . title } </h3>
86
+ <span id="status-${ app . script } " class="text-green-500 hidden">
87
+ <i class="fas fa-check-circle"></i>
88
+ </span>
89
+ </div>
83
90
<p class="text-sm text-gray-600 dark:text-gray-400 mb-3 flex-1">${ app . description } </p>
84
91
</div>
85
92
</div>
86
93
` ;
87
94
95
+ updateAppStatus ( app . script ) ;
88
96
card . addEventListener ( 'click' , async ( ) => {
89
- if ( ! isConnected ) {
90
- showAlert ( 'Please connect to a device first using USB, WiFi or Bluetooth' ) ;
91
- return ;
92
- }
93
-
94
- // Add loading state to the clicked card
95
- const originalContent = card . innerHTML ;
96
- card . innerHTML = `
97
- <div class="h-full flex items-center justify-center p-4">
98
- <i class="fas fa-circle-notch fa-spin text-${ app . color } -500 text-xl mr-2"></i>
99
- <span>Launching ${ app . title } ...</span>
100
- </div>
101
- ` ;
102
-
103
- try {
104
- const response = await fetch ( `/check_app_status/${ app . script } ` ) ;
105
-
106
- if ( ! response . ok ) {
107
- throw new Error ( 'Failed to check app status' ) ;
108
- }
109
-
110
- const data = await response . json ( ) ;
111
-
112
- if ( data . status === 'running' ) {
113
- showAlert ( `${ app . title } is already running!` ) ;
114
- card . innerHTML = originalContent ;
115
- return ;
116
- }
117
-
118
- await launchApplication ( app . script ) ;
119
- card . innerHTML = originalContent ;
120
- } catch ( error ) {
121
- console . error ( 'Error launching app:' , error ) ;
122
- showAlert ( `Failed to launch ${ app . title } : ${ error . message } ` ) ;
123
- card . innerHTML = originalContent ;
124
- }
97
+ await handleAppClick ( app , card ) ;
125
98
} ) ;
126
99
127
100
appGrid . appendChild ( card ) ;
128
101
} ) ;
129
102
}
130
103
104
+ async function handleAppClick ( app , card ) {
105
+ const statusElement = document . getElementById ( `status-${ app . script } ` ) ;
106
+ if ( statusElement && ! statusElement . classList . contains ( 'hidden' ) ) {
107
+ return ;
108
+ }
109
+
110
+ if ( ! isConnected ) {
111
+ showAlert ( 'Please connect to a device first using USB, WiFi or Bluetooth' ) ;
112
+ return ;
113
+ }
114
+
115
+ const originalContent = card . innerHTML ; // Add loading state to the clicked card
116
+ card . innerHTML = `
117
+ <div class="h-full flex items-center justify-center p-4">
118
+ <i class="fas fa-circle-notch fa-spin text-${ app . color } -500 text-xl mr-2"></i>
119
+ <span>Launching ${ app . title } ...</span>
120
+ </div>
121
+ ` ;
122
+
123
+ try {
124
+ const response = await fetch ( `/check_app_status/${ app . script } ` ) ;
125
+
126
+ if ( ! response . ok ) {
127
+ throw new Error ( 'Failed to check app status' ) ;
128
+ }
129
+
130
+ const data = await response . json ( ) ;
131
+
132
+ await launchApplication ( app . script ) ;
133
+ card . innerHTML = originalContent ;
134
+ updateAppStatus ( app . script ) ; // Update status after launch
135
+ } catch ( error ) {
136
+ console . error ( 'Error launching app:' , error ) ;
137
+ showAlert ( `Failed to launch ${ app . title } : ${ error . message } ` ) ;
138
+ card . innerHTML = originalContent ;
139
+ }
140
+ }
141
+
142
+ async function updateAppStatus ( appName ) {
143
+ try {
144
+ const response = await fetch ( `/check_app_status/${ appName } ` ) ;
145
+ if ( ! response . ok ) return ;
146
+
147
+ const data = await response . json ( ) ;
148
+ const statusElement = document . getElementById ( `status-${ appName } ` ) ;
149
+ const cardElement = document . getElementById ( `card-${ appName } ` ) ;
150
+
151
+ if ( statusElement && cardElement ) {
152
+ if ( data . status === 'running' ) {
153
+ statusElement . classList . remove ( 'hidden' ) ;
154
+ cardElement . classList . add ( 'cursor-not-allowed' ) ;
155
+ cardElement . classList . remove ( 'cursor-pointer' ) ;
156
+ cardElement . classList . remove ( 'hover:shadow-lg' ) ;
157
+ cardElement . classList . add ( 'opacity-60' ) ;
158
+ } else {
159
+ statusElement . classList . add ( 'hidden' ) ;
160
+ cardElement . style . pointerEvents = 'auto' ;
161
+ cardElement . classList . remove ( 'cursor-not-allowed' ) ;
162
+ cardElement . classList . add ( 'cursor-pointer' ) ;
163
+ cardElement . classList . add ( 'hover:shadow-lg' ) ;
164
+ cardElement . classList . remove ( 'opacity-80' ) ;
165
+ }
166
+ }
167
+ } catch ( error ) {
168
+ console . error ( 'Error checking app status:' , error ) ;
169
+ }
170
+ }
171
+
172
+ // Periodically check all app statuses
173
+ function startAppStatusChecker ( ) {
174
+ checkAllAppStatuses ( ) ;
175
+ setInterval ( checkAllAppStatuses , 200 ) ;
176
+ }
177
+
178
+ // Check status of all apps
179
+ function checkAllAppStatuses ( ) {
180
+ const appGrid = document . getElementById ( 'app-grid' ) ;
181
+ if ( ! appGrid ) return ;
182
+
183
+ const apps = appGrid . querySelectorAll ( '[id^="status-"]' ) ;
184
+ apps . forEach ( statusElement => {
185
+ const appName = statusElement . id . replace ( 'status-' , '' ) ;
186
+ updateAppStatus ( appName ) ;
187
+ } ) ;
188
+ }
189
+
131
190
// Set up category filter with fixed options
132
191
function setupCategoryFilter ( apps ) {
133
192
const categorySelect = document . querySelector ( 'select' ) ;
@@ -179,6 +238,7 @@ function filterAppsByCategory(category, allApps) {
179
238
appGrid . style . opacity = '0' ;
180
239
setTimeout ( ( ) => {
181
240
appGrid . style . opacity = '1' ;
241
+ checkAllAppStatuses ( ) ;
182
242
} , 10 ) ;
183
243
} , 300 ) ;
184
244
}
0 commit comments