Jump to content

KT Walrus

Clients
  • Joined

  • Last visited

  1. I’ve wasted enough of my time trying to help you fix your product. From my point of view, once I’ve let you know there is an issue, my role ends. I’ve let you know, and now it is up to you as to whether this is something you will fix or not. I didn’t really appreciate your requesting that I spend more time reposting in another forum. I don’t work for you.
  2. You are right, I think. It is only wrong for colored forums. When you fix this, can you also fix the difference forum positions in the condensed view and the expanded view. I think the only thing that should be different between both views is the expanded view has the topic blurb.
  3. I don’t understand your reply. The condensed view is showing both white and blue unread dots with no rhyme or rhythm as to why I’m seeing both in the same list. I have always had the account settings to go to the first unread post. @Marc So, why both white and blue dots in the condensed view and only blue dots in the expanded view?
  4. Just noticed the mix of dot colors is only when viewing in condensed mode. When viewing in expanded mode, all dots seem to be blue and honor the “go to first unread post” setting. Maybe this is just a bug in condensed view?
  5. I’m trying to figure understand the purpose of the white unread dots that just started appearing in place of some blue unread dots. I think it might mean that it takes you to the first post in the topic even if you had already read previously that topic but it now might have new unread replies. But, this makes no sense to me. I always want to jump to the first unread reply. As it is now, I seem to get a mixture of white and blue unread dots and some of the white dots were previously viewed before. BTW, I use Dark mode so the new dots are white for me.
  6. Just tried it again after changing from expanded view to condensed view. Same issue except for 1 or 2 times it worked properly. I noticed, I think, that when it worked properly, the underlying list seemed to refresh as soon as I unchecked the single selected forum in the filter and not wait for the popup to be dismissed. So, this might be a timing issue in JavaScript on very fast devices and might not be reproducible on slower devices. I’m not sure what is happening but since there is another similar bug in showing the last edit changes after submitting the reply, these two problems might be the same issue. Sometimes, these JavaScript gets the refresh wrong after changing something without a full page reload. Also, condensed view has the forum link after the poster/post date and the expanded view has this link before the poster/date. The forum link is much easier to tap in condensed view. Shouldn’t both views show the forum link in the same position, maybe to the right since it is easier to tap there?
  7. I thought the fix to add a refresh icon to the PWA nav bar would give a workaround to the issue of needing a manual refresh when filtering the list by tapping on the forum link under the topic titles and then unchecking that forum in the “Showing 1 forum” filter. But, the whole Fluid View still has several UX issues. After unchecking, the correct message of “Showing all forums” is shown as the current state of the filter, but the topics list still shows only topics from the single forum. No auto-refresh was done. If I then click on the new refresh icon, the page is reloaded but the list and filter again show only 1 forum’s topics. If I reset the filter again to uncheck that single forum, but then tap the Forums link in the breadcrumbs, the list is reloaded properly showing all forums again. Another related issue is it is very difficult to tap on the Forum link under the topic titles now. I think the Forum link and the Topic area link to view the topic might be too close for touch devices. Not sure on that one. Frankly, you should either fix the UI to work properly or not have a forum name under title be a clickable link at all. It would probably be better to tap the “Showing all” filter and select the forums you want to see. This filter seems to work as expected, I think. I am using an iPhone 16 Pro Max and the PWA. I haven’t tried this in the browser or on another device. For the GA, I vote to make the forum links inactive so the only way to filter Fluid View is through the Show filter dialog.
  8. BTW, I had the same opinion about coding and AI until I started a new PHP side-project from scratch a couple of weeks ago. But these past few weeks using Claude 3.5 Sonnet for PHP has been completely eye opening to me. For example, Claude has helped greatly in my coding of a PDO DB class that is full featured and totally ready for production use. Also, I’ve had tremendous success with Repositories and DTOs/Entities in a way that are also of very high quality (complete with very good data validation rules specific to my database). I’m currently working on a cli for my app and adding RabbitMQ for sending data crud operations to the admin server. Anyway, I would not be able to have coded all this in such a short time without Claude’s help. Another exciting development in AI for software development is the release of Deepseek R1 last week. R1 is not much of a PHP coder (in my limited experience), but the fact that it is the first reasoning model I know of that shows it’s thinking before it generates a response is a real game changer for me as a developer. I can see all the possibilities that R1 considered and often abandoned and this makes me consider way more things as I create new code that weren’t on my mind before asking the AI for it’s thoughts. The last question I almost always ask the AI before end a chat, is what more can it do for using this code in production. This often lists 5 or 10 areas that should be worked on further and then I continue the chat with having the AI prototyping a solution that addresses my particular needs and applying the solutions to the code it has written before. Sure, the code produced by Claude is usually prototype quality but I know enough about writing good well designed code to be able to rework/refactor the code for production use. This has cut down the time to add a feature from a week or two to a day or two and my code is of higher quality than without the AI’s help. I’m also starting to explore having AI help me in writing tests for my PHP app. Pest 2.0, the new replacement for PHPUnit is a great test runner that adds code coverage analysis and many other features that help give you confidence that you have enough tests to properly take your code to production and to have the confidence that future changes won’t introduce regressions into the rest of the app.
  9. This is fantastic news. Thanks for giving the PWA a little ❤️ before the GA ships. There are still a few places in the UI where some automatic refreshes are missing (at least on my fast iPhone). These might be timing issues with JavaScript so sometimes works but most times don’t work for me. Also, push notification badges don’t show on the PWA icon, but this has been a bug since you first added push notifications to the suite and has never been fixed. Other than that, v5 is a huge improvement on mobile and using the PWA. Thanks again for the reload button in the PWA.
  10. BTW, if you haven’t tried Deepseek R1 yet, you should. It shows you in minute detail about it’s reasoning in coming up with a response. So, even if it gets the answers wrong, you can learn what you need to solve the problem the first time and not miss thinking about edge cases. I have been running R1 prompts first before using Claude to get Claude to write me code. I’ve only been using R1 for a couple of days now, but so far, it has helped me to think about coding problems in a way I wasn’t before.
  11. I didn’t mean to imply that your devs don’t have the skills to code. I recently started using AI as my coding assistant both through Claude and Copilot and it has made me 10x faster at producing new code so small tasks like implementing pull-to-refresh which now only takes an hour or so. Prior to Claude this would have taken a day for me to code and even longer to get the bugs out. So, I would usually reach for a JS or PHP package to accelerate adding features to my code. Anyway, AI makes good programmers code way faster in my recent experience. Now that I thought of using AI to add missing features to v3, I’m feeling a lot better about your decision to not make the mobile UX a good one for non-technical users in the first release. I still do not have the skills to debug JS, but at least I have Claude to help me now.
  12. I use Claude 3.5 Sonnet via Theo’s new chat SaaS which provides a fast basic chat wrapper around several LLMs. There are tons of these kind of site so you would have no problem finding one that can help you with any coding questions. Note, that if you want to have AI assist you in actual coding, use CoPilot in your favorite PHP editor like VS Code or the fantastic PHPStorm. Here is a link to Theo’s chat SaaS: https://t3.chat
  13. Here is Claude’s response to adding pull to refresh in PWAs on iOS. Don’t know if this all works but Claude usually writes good JS for me. Here's the updated version of the PullToRefresh class that only enables the functionality for iOS devices: ```javascript class PullToRefresh { constructor(options) { // First check if we should initialize on this platform if (!this.shouldInitialize()) { return; } this.options = { target: document.querySelector("body"), threshold: 60, onRefresh: () => location.reload(), ...options, }; this.startY = 0; this.currentY = 0; this.dragging = false; this.refreshing = false; this.init(); } shouldInitialize() { // Check for iOS devices const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) || (navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1); // Check if it's running as a PWA const isStandalone = window.navigator.standalone || window.matchMedia("(display-mode: standalone)").matches; // Only initialize for iOS devices running as PWA return isIOS && isStandalone; } init() { // Create refresh indicator element this.indicator = document.createElement("div"); this.indicator.setAttribute("aria-label", "Pull to refresh indicator"); this.indicator.style.cssText = ` position: fixed; top: 0; left: 0; right: 0; height: 50px; display: flex; align-items: center; justify-content: center; transform: translateY(-100%); transition: transform 0.2s; background-color: #f0f0f0; z-index: 9999; font-family: -apple-system, system-ui, sans-serif; `; document.body.prepend(this.indicator); // Create loading spinner this.spinner = document.createElement("div"); this.spinner.style.cssText = ` display: none; width: 20px; height: 20px; margin-right: 10px; border: 2px solid #007AFF; border-top-color: transparent; border-radius: 50%; animation: spin 1s linear infinite; `; // Add spinner animation const style = document.createElement("style"); style.textContent = ` @keyframes spin { to { transform: rotate(360deg); } } `; document.head.appendChild(style); this.indicator.appendChild(this.spinner); // Add text element this.textElement = document.createElement("span"); this.indicator.appendChild(this.textElement); // Add event listeners with passive: false for better performance this.options.target.addEventListener( "touchstart", (e) => this.onTouchStart(e), { passive: false } ); this.options.target.addEventListener( "touchmove", (e) => this.onTouchMove(e), { passive: false } ); this.options.target.addEventListener("touchend", (e) => this.onTouchEnd(e), { passive: false, }); } updateUI(distance) { const progress = (distance / this.options.threshold) * 100; this.spinner.style.transform = `rotate(${progress * 3.6}deg)`; this.spinner.style.display = "block"; this.textElement.textContent = distance >= this.options.threshold ? "Release to refresh" : "Pull to refresh"; } onTouchStart(e) { if (window.scrollY === 0 && !this.refreshing) { this.dragging = true; this.startY = e.touches[0].pageY; } } onTouchMove(e) { if (!this.dragging) return; this.currentY = e.touches[0].pageY; const distance = this.currentY - this.startY; if (distance > 0) { e.preventDefault(); const pullDistance = Math.min(distance * 0.5, this.options.threshold); this.indicator.style.transform = `translateY(${pullDistance}px)`; this.updateUI(pullDistance); } } onTouchEnd() { if (!this.dragging) return; this.dragging = false; const distance = this.currentY - this.startY; if (distance >= this.options.threshold) { this.refreshing = true; this.spinner.style.display = "block"; this.textElement.textContent = "Refreshing..."; this.spinner.style.animation = "spin 1s linear infinite"; this.options.onRefresh() .finally(() => { this.refreshing = false; this.indicator.style.transform = "translateY(-100%)"; this.spinner.style.animation = "none"; }) .catch((error) => { console.error("Refresh failed:", error); this.textElement.textContent = "Refresh failed"; setTimeout(() => { this.indicator.style.transform = "translateY(-100%)"; }, 1000); }); } else { this.indicator.style.transform = "translateY(-100%)"; } } // Method to manually destroy the instance destroy() { if (this.indicator) { this.indicator.remove(); } if (this.options.target) { this.options.target.removeEventListener("touchstart", this.onTouchStart); this.options.target.removeEventListener("touchmove", this.onTouchMove); this.options.target.removeEventListener("touchend", this.onTouchEnd); } } } // Usage example const ptr = new PullToRefresh({ target: document.querySelector("#content"), onRefresh: async () => { try { // Your refresh logic here await new Promise((resolve) => setTimeout(resolve, 1500)); location.reload(); } catch (error) { console.error("Refresh failed:", error); throw error; // Rethrow to trigger error handling in the class } }, }); ``` This updated version includes: 1. Platform detection through `shouldInitialize()` method 2. Better iOS detection including newer iPads 3. PWA (standalone mode) detection 4. Improved visual feedback with a spinning loader 5. Better error handling 6. Improved accessibility 7. Performance optimizations with passive event listeners 8. Cleanup method through `destroy()` 9. More iOS-native feeling styling To use it: ```javascript // Initialize const ptr = new PullToRefresh({ target: document.querySelector("#content"), threshold: 60, // Optional: customize pull distance onRefresh: async () => { // Your custom refresh logic await fetchNewData(); }, }); // Later, if needed, cleanup ptr.destroy(); ``` The pull-to-refresh will now only initialize on iOS devices running as a PWA. On other platforms, it will silently do nothing, allowing the native pull-to-refresh behavior (if any) to work as expected. Remember to still include the appropriate manifest.json settings: ```json { "display": "standalone", "apple-mobile-web-app-capable": "yes" } ``` This implementation provides a more native-feeling experience for iOS PWA users while not interfering with other platforms' built-in behaviors.
  14. Here is Claude 3.5 Sonnet’s answer to adding “pull to refresh” to a PWA on iOS. Claude on adding pull to refresh Yes! Here's a JavaScript solution to implement pull-to-refresh functionality in Progressive Web Apps on iOS. This code uses the touchstart, touchmove, and touchend events to create a native-feeling pull-to-refresh experience: ```javascript class PullToRefresh { constructor(options) { this.options = { target: document.querySelector("body"), threshold: 60, // Required pull distance in pixels onRefresh: () => location.reload(), ...options, }; this.startY = 0; this.currentY = 0; this.dragging = false; this.refreshing = false; this.init(); } init() { // Create refresh indicator element this.indicator = document.createElement("div"); this.indicator.style.cssText = ` position: fixed; top: 0; left: 0; right: 0; height: 50px; display: flex; align-items: center; justify-content: center; transform: translateY(-100%); transition: transform 0.2s; `; document.body.prepend(this.indicator); // Add event listeners this.options.target.addEventListener("touchstart", (e) => this.onTouchStart(e) ); this.options.target.addEventListener("touchmove", (e) => this.onTouchMove(e)); this.options.target.addEventListener("touchend", (e) => this.onTouchEnd(e)); } onTouchStart(e) { if (window.scrollY === 0 && !this.refreshing) { this.dragging = true; this.startY = e.touches[0].pageY; } } onTouchMove(e) { if (!this.dragging) return; this.currentY = e.touches[0].pageY; const distance = this.currentY - this.startY; if (distance > 0) { e.preventDefault(); const pullDistance = Math.min(distance * 0.5, this.options.threshold); this.indicator.style.transform = translateY(${pullDistance}px); this.indicator.textContent = pullDistance >= this.options.threshold ? "Release to refresh" : "Pull to refresh"; } } onTouchEnd() { if (!this.dragging) return; this.dragging = false; const distance = this.currentY - this.startY; if (distance >= this.options.threshold) { this.refreshing = true; this.indicator.textContent = "Refreshing..."; this.options.onRefresh().finally(() => { this.refreshing = false; this.indicator.style.transform = "translateY(-100%)"; }); } else { this.indicator.style.transform = "translateY(-100%)"; } } } // Usage example const ptr = new PullToRefresh({ target: document.querySelector("#content"), onRefresh: async () => { // Your refresh logic here await new Promise((resolve) => setTimeout(resolve, 1500)); location.reload(); }, }); ``` To use this in your PWA: 1. Add the code to your project 2. Initialize it with your desired target element and refresh callback 3. Add the following to your manifest.json to enable pull-to-refresh: ```json { "display": "standalone", "apple-mobile-web-app-capable": "yes" } ``` Key features of this implementation: - Works on iOS Safari and when installed as a PWA - Smooth animation with native feel - Customizable threshold and refresh callback - Visual indicator with status messages - Prevents default scroll behavior when pulling - Handles edge cases and cleanup You can customize the appearance of the refresh indicator by modifying the CSS in the init() method. You might also want to add a loading spinner or other visual feedback during the refresh operation. Note that this is a basic implementation - you might want to add: 1. Better error handling 2. Animation for the refresh indicator 3. Custom styling to match your app's design 4. Support for different pull distances 5. Better accessibility features Remember that while this works well for iOS, Android typically has built-in pull-to-refresh functionality that you might want to preserve, so you may want to add platform detection and only enable this for iOS devices.