| 2810 | //============================================================================= |
| 2811 | |
| 2812 | String selectFileFromSD() { |
| 2813 | if (!SD.begin()) { |
| 2814 | showErrorMessage("SD Card not found"); |
| 2815 | return ""; |
| 2816 | } |
| 2817 | |
| 2818 | const int MAX_FILES = 30; |
| 2819 | String files[MAX_FILES]; |
| 2820 | int fileCount = 0; |
| 2821 | |
| 2822 | File root = SD.open("/"); |
| 2823 | if (!root) { |
| 2824 | showErrorMessage("Cannot open SD"); |
| 2825 | return ""; |
| 2826 | } |
| 2827 | |
| 2828 | File file = root.openNextFile(); |
| 2829 | while (file && fileCount < MAX_FILES) { |
| 2830 | String filename = file.name(); |
| 2831 | if (!file.isDirectory() && (filename.endsWith(".txt") || filename.endsWith(".ducky") || |
| 2832 | filename.endsWith(".TXT") || filename.endsWith(".DUCKY"))) { |
| 2833 | files[fileCount++] = filename; |
| 2834 | } |
| 2835 | file = root.openNextFile(); |
| 2836 | } |
| 2837 | root.close(); |
| 2838 | |
| 2839 | if (fileCount == 0) { |
| 2840 | showErrorMessage("No files found"); |
| 2841 | return ""; |
| 2842 | } |
| 2843 | |
| 2844 | int selected = 0, scrollOffset = 0; |
| 2845 | int lastSelected = -1, lastScrollOffset = -1; |
| 2846 | bool exitMenu = false; |
| 2847 | int menuStartY = 60, menuItemHeight = 25; |
| 2848 | int maxVisibleItems = (tftHeight - menuStartY - 50) / menuItemHeight; |
| 2849 | if (maxVisibleItems > fileCount) maxVisibleItems = fileCount; |
| 2850 | |
| 2851 | while (!exitMenu) { |
| 2852 | if (selected != lastSelected || scrollOffset != lastScrollOffset) { |
| 2853 | tft.fillScreen(bruceConfig.bgColor); |
| 2854 | tft.drawRect(5, 5, tftWidth - 10, tftHeight - 10, TFT_WHITE); |
| 2855 | |
| 2856 | tft.setTextColor(TFT_WHITE, bruceConfig.bgColor); |
| 2857 | tft.setTextSize(2); |
| 2858 | tft.setCursor((tftWidth - strlen("SD CARD FILES") * 12) / 2, 15); |
| 2859 | tft.print("SD CARD FILES"); |
| 2860 | tft.setTextSize(1); |
| 2861 | |
| 2862 | tft.setTextColor(TFT_YELLOW, bruceConfig.bgColor); |
| 2863 | tft.setCursor(20, 40); |
| 2864 | tft.print("Found: "); |
| 2865 | tft.print(fileCount); |
| 2866 | tft.print(" files"); |
| 2867 | |
| 2868 | for (int i = 0; i < maxVisibleItems && (scrollOffset + i) < fileCount; i++) { |
| 2869 | int fileIdx = scrollOffset + i; |
no test coverage detected