דילוג לתוכן
  • חוקי הפורום
  • פופולרי
  • לא נפתר
  • משתמשים
  • חיפוש גוגל בפורום
  • צור קשר
עיצובים
  • בהיר
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • כהה
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • ברירת מחדל (ללא עיצוב (ברירת מחדל))
  • ללא עיצוב (ברירת מחדל)
כיווץ
מתמחים טופ
מחנה ידידיםמ

מחנה ידידים

@מחנה ידידים
הפסקת מעקב מעקב
אודות
פוסטים
2.1k
נושאים
108
שיתופים
0
קבוצות
0
עוקבים
12
עוקב אחרי
9

פוסטים

פוסטים אחרונים הגבוה ביותר שנוי במחלוקת

  • מדריך | בניית אפליקציה בקלוד (באתר ובאפליקציה)
    מחנה ידידיםמ מחנה ידידים

    אז למי שלא ידע, קלוד יודע ליצור אפליקציות...

    ㅤ

    • שלב ראשון - נכנסים לכאן ופותחים חשבון חדש.

    לאחר מכן יפתח לכם המסך הראשי:
    ef2338bb-81ed-48d4-b5d9-537b2d3fb33f-image.jpeg

    אנחנו נבנה את האפליקציה בקוטלין.

    • ניצור פרומפט באמצעות כלי Ai כלשהו.
      חשוב: צריך שבפרומפט תהיה התייחסות לקבצים שנצרף, שמיועדים לבנייה. כדאי גם לבקש שיתן גם APK וגם קוד מקור.

    אלו הקבצים שצריך לצרף:

    • aapt2-8.2.0-10154469-linux.jar

    • r8lib.jar

    • trove4j.jar

    • android.jar

    • kotlin-stdlib-1.9.22.jar

    • קומפיילר קוטלין - בדרייב

    נצרף את הקבצים בלחיצה על כפתור ההוספה e8bd3522-0e32-47d9-9429-630793f0fbe1-image.jpeg

    • נדביק את הפרומפט ונשלח.

    עכשיו קלוד יעבוד, יתכן ויגמר הטוקנים באמצע - המתינו כמה שעות שיתמלא שוב ושלחו לו "Go on".
    בסוף הוא ייצא לכם קובץ APK חתום + קוד המקור בזיפ.

    ㅤ

    בהצלחה!

    עזרה הדדית - בניית ופיתוח אפליקציות

  • שיתוף | אתר לגרסאות!
    מחנה ידידיםמ מחנה ידידים

       בהמשך לנושא זה האתר עלה.

    כתובת האתר - https://mahaneh-iedidim.github.io/site


    אשמח להערות והארות.
    @מישהו12 הפרסומת בסדר? 😊

    עזרה הדדית - שיאומי f21 pro ו +f21 pro

  • המלצה | קלוד יודע ליצור אפליקציות!
    מחנה ידידיםמ מחנה ידידים

    קלוד (באפליקציה ובאתר) יכול ליצור אפליקציות שלמות ואפילו לחתום אותן!
    הצלחתי ליצור איתו עכשיו לאנצ'ר בסגנון C2.

    עובד גם בחינמי! נסו והיווכחו

    עזרה הדדית - בינה מלאכותית

  • מדריך | הפעלת המחווה לפתיחת מגירת האפליקציות במסך הבית!
    מחנה ידידיםמ מחנה ידידים

    אחרי הרבה עבודה...

    המדריך באדיבות קלוד סונט 5

    צילומי מסך:

    3385ecd8-6500-4267-b4f1-3d00e4a00ab9-image.jpeg

    @10110000 @שניאור-שמח @נוחעם-FM @שלום-כהן

    מדריך: הוספת מחווה לפתיחת מגירת האפליקציות ב-Launcher3QuickStep

    מדריך זה מתעד את השלבים המדויקים שביצעתי כדי לפתור בעיה נפוצה בבניות מבוססות
    Launcher3QuickStep (AOSP) על מכשירים עם מסך ביחס ממדים חריג (כמו Qin F21 Pro)
    כאשר החלקה למעלה במסך הבית לא פותחת את מגירת האפליקציות.


    שורש הבעיה

    ב-Launcher3QuickStep הסטנדרטי, המחווה של החלקה למעלה כדי לפתוח את המגירה
    מיושמת דרך מחלקה בשם PortraitStatesTouchController, שנרשמת בתוך
    QuickstepLauncher.createTouchControllers().

    הבעיה: הרישום הזה מותנה בבדיקה DeviceProfile.isVerticalBarLayout().
    במכשירים עם יחס ממדים חריג (מסכים קטנים/כמעט-מרובעים), הפונקציה הזו מחזירה
    true בטעות — מה שגורם לקוד לעבור לענף אחר (המיועד למכשירים עם hotseat
    אנכי, כמו טאבלטים/מכשירים מתקפלים), שבו PortraitStatesTouchController
    לא נרשם בכלל. התוצאה: אין שום דרך במגע לפתוח את המגירה.

    איך לזהות את זה בעצמכם ב-APK אחר

    # אחרי פירוק עם apktool:
    grep -n "createTouchControllers" smali_classes2/com/android/launcher3/uioverrides/QuickstepLauncher.smali
    

    חפשו בגוף המתודה הזו קריאה ל-DeviceProfile;->isVerticalBarLayout()Z — אם
    הענף שמוסיף PortraitStatesTouchController תלוי בבדיקה הזו, זו אותה בעיה.


    הפתרון שבחרתי

    במקום "לתקן" את isVerticalBarLayout() (מסוכן — הוא משפיע על עוד המון
    לוגיקת מסך), יצרתי controller עצמאי חדש שמזהה בעצמו החלקה למעלה על מסך
    הבית ופותח את המגירה — בלי שום תלות בענף השבור. הוא נרשם תמיד, בלי תנאי,
    כך שהוא עובד גם אם isVerticalBarLayout() ממשיך "לטעות".

    כלים נדרשים

    • MT Manager

    מידע חשוב: המדריך דורש רוט עם הרשאות כתיבה

    שלב 1 — פתיחת ה-APK לעריכה

    1. במסך הקבצים של MT Manager, אתרו את ה-APK ולחצו עליו (לא לחיצה ארוכה) —
      ייפתח תפריט "פתח באמצעות".
    2. בחרו הצג.
    3. תיפתח תצוגת עץ שמראה את מבנה ה-APK כולל classes.dex,
      classes2.dex וכו', כל אחד ניתן לניווט עד רמת חבילות ה-Smali.
    4. נווטו לתוך classes2.dex (שם נמצא כל קוד ה-launcher עצמו ברוב הבניות) →
      com/android/launcher3/uioverrides/touchcontrollers/.

    שלב 2 — יצירת המחלקה החדשה

    בתוך התיקייה touchcontrollers/ שמצאתם, צרו קובץ Smali חדש (לחצו על הקובץ הראשון לחיצה ארוכה ובחרו "הוסף") בשם בדיוק:

    SimpleAppDrawerSwipeController.smali
    
    .class public Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;
    .super Ljava/lang/Object;
    .source "SimpleAppDrawerSwipeController.java"
    
    # interfaces
    .implements Lcom/android/launcher3/util/TouchController;
    
    
    # instance fields
    .field private mCanIntercept:Z
    
    .field private mDownX:F
    
    .field private mDownY:F
    
    .field private final mLauncher:Lcom/android/launcher3/Launcher;
    
    .field private final mSwipeSlop:F
    
    
    # direct methods
    .method public constructor <init>(Lcom/android/launcher3/Launcher;)V
        .locals 2
        .param p1, "launcher"    # Lcom/android/launcher3/Launcher;
    
        invoke-direct {p0}, Ljava/lang/Object;-><init>()V
    
        iput-object p1, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mLauncher:Lcom/android/launcher3/Launcher;
    
        invoke-static {p1}, Landroid/view/ViewConfiguration;->get(Landroid/content/Context;)Landroid/view/ViewConfiguration;
    
        move-result-object v0
    
        invoke-virtual {v0}, Landroid/view/ViewConfiguration;->getScaledTouchSlop()I
    
        move-result v0
    
        mul-int/lit8 v0, v0, 0x4
    
        int-to-float v0, v0
    
        iput v0, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mSwipeSlop:F
    
        return-void
    .end method
    
    
    # virtual methods
    .method public onControllerInterceptTouchEvent(Landroid/view/MotionEvent;)Z
        .locals 6
        .param p1, "ev"    # Landroid/view/MotionEvent;
    
        invoke-virtual {p1}, Landroid/view/MotionEvent;->getActionMasked()I
    
        move-result v0
    
        const/4 v1, 0x0
    
        if-nez v0, :cond_1
    
        iget-object v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mLauncher:Lcom/android/launcher3/Launcher;
    
        sget-object v3, Lcom/android/launcher3/LauncherState;->NORMAL:Lcom/android/launcher3/LauncherState;
    
        invoke-virtual {v2, v3}, Lcom/android/launcher3/Launcher;->isInState(Lcom/android/launcher3/statemanager/BaseState;)Z
    
        move-result v2
    
        iput-boolean v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mCanIntercept:Z
    
        invoke-virtual {p1}, Landroid/view/MotionEvent;->getX()F
    
        move-result v2
    
        iput v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownX:F
    
        invoke-virtual {p1}, Landroid/view/MotionEvent;->getY()F
    
        move-result v2
    
        iput v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownY:F
    
        return v1
    
        :cond_1
        iget-boolean v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mCanIntercept:Z
    
        if-nez v2, :cond_2
    
        return v1
    
        :cond_2
        const/4 v2, 0x2
    
        if-eq v0, v2, :cond_3
    
        return v1
    
        :cond_3
        invoke-virtual {p1}, Landroid/view/MotionEvent;->getPointerCount()I
    
        move-result v2
    
        const/4 v3, 0x1
    
        if-eq v2, v3, :cond_4
    
        return v1
    
        :cond_4
        iget v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownY:F
    
        invoke-virtual {p1}, Landroid/view/MotionEvent;->getY()F
    
        move-result v4
    
        sub-float/2addr v2, v4
    
        invoke-virtual {p1}, Landroid/view/MotionEvent;->getX()F
    
        move-result v4
    
        iget v5, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownX:F
    
        sub-float/2addr v4, v5
    
        invoke-static {v4}, Ljava/lang/Math;->abs(F)F
    
        move-result v4
    
        iget v5, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mSwipeSlop:F
    
        cmpl-float v5, v2, v5
    
        if-lez v5, :cond_5
    
        cmpl-float v5, v2, v4
    
        if-lez v5, :cond_5
    
        iget-object v5, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mLauncher:Lcom/android/launcher3/Launcher;
    
        invoke-virtual {v5}, Lcom/android/launcher3/Launcher;->getStateManager()Lcom/android/launcher3/statemanager/StateManager;
    
        move-result-object v5
    
        sget-object v0, Lcom/android/launcher3/LauncherState;->ALL_APPS:Lcom/android/launcher3/LauncherState;
    
        invoke-virtual {v5, v0}, Lcom/android/launcher3/statemanager/StateManager;->goToState(Lcom/android/launcher3/statemanager/BaseState;)V
    
        const/4 v0, 0x1
    
        return v0
    
        :cond_5
        return v1
    .end method
    
    .method public onControllerTouchEvent(Landroid/view/MotionEvent;)Z
        .locals 1
        .param p1, "ev"    # Landroid/view/MotionEvent;
    
        const/4 v0, 0x1
    
        return v0
    .end method
    

    איך זה עובד, בקצרה:

    • onControllerInterceptTouchEvent עוקב אחרי כל מגע: ב-ACTION_DOWN הוא בודק
      שהמסך במצב NORMAL (מסך הבית, לא במגירה/overview כבר) ושומר את נקודת
      ההתחלה.
    • ב-ACTION_MOVE, אם התזוזה האנכית כלפי מעלה עוברת סף (4 × touch-slop של המערכת) והיא דומיננטית יותר מהתזוזה האופקית (כלומר מחווה אנכית ולא גרירה
      בין מסכים) — הוא קורא ל-goToState(ALL_APPS) ומחזיר true, מה שגורם
      ל-DragLayer "לגנוב" את המגע משאר הרכיבים.
    • onControllerTouchEvent פשוט בולע את המשך המחווה כדי שלא יקרו תופעות לוואי
      בזמן שהמעבר למגירה כבר קורה.

    שלב 3 — רישום ה-controller

    חזרו תיקייה אחת אחורה (uioverrides/) ופתחו לעריכה את
    QuickstepLauncher.smali. חפשו בתוך הקובץ (יש חיפוש טקסט בעורך) את המתודה:

    .method public createTouchControllers()[Lcom/android/launcher3/util/TouchController;
    

    בתוך המתודה הזו, מיד אחרי השורה הראשונה שמוסיפה פריט ל-ArrayList (זו
    שמוסיפה את ה-DragController — תזהו אותה לפי getDragController() ממש
    מעליה), הוסיפו את שלוש השורות הבאות:

        invoke-virtual {v2, v3}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z
    
        new-instance v3, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;
    
        invoke-direct {v3, p0}, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;-><init>(Lcom/android/launcher3/Launcher;)V
    
        invoke-virtual {v2, v3}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z
    

    חשוב לפני שאתם מדביקים: v2 בקוד הזה הוא ה-register שמחזיק את
    ה-ArrayList<TouchController>, ו-v3 הוא register שחייב להיות פנוי
    לשימוש חוזר באותה נקודה — בדקו בעצמכם בקובץ שלכם (חפשו למעלה איפה v3
    משמש לאחרונה, ולמטה איפה הוא משמש הבא). אם v3 לא פנוי שם, או אם .locals
    בתחילת המתודה נמוך מדי בשביל ה-register שבחרתם — MT Manager יזרוק שגיאת קימפול Smali ברגע השמירה/יציאה מהעורך, ותצטרכו לבחור register אחר ואולי
    להעלות את מספר ה-.locals.

    שלב 4 — שמירה וקימפול

    צאו מעורך ה-Smali (בדרך כלל כפתור "שמור" או חץ אחורה) (לא לסמן את "חתימה אוטומטית"!)
    — MT Manager יקמפל
    אוטומטית את השינויים בחזרה ל-dex ברגע הזה. אם יש שגיאת תחביר Smali היא
    תופיע כאן; אם לא, ה-APK בתיקייה שערכתם כבר מעודכן.


    בהצלחה!

    לתגובות

    מדריכים -שיאומי f21 pro ו +f21 pro

  • המלצה | סקריפט לטמפרמונקי לשיפור נוחות השימוש בפורום!
    מחנה ידידיםמ מחנה ידידים

    אחרי הרבה עבודה...

    // ==UserScript==
    // @name         Mitmachim Forum Ultimate Enhancements
    // @namespace    http://tampermonkey.net/
    // @version      4.9
    // @description  החזרת מנגנון ההזרקה המדויק של גרסה 3.4, שילוב צ'אט אוטומטי ותצוגה מקדימה
    // @author       ישראל מאיר שגיב & Gemini
    // @match        https://mitmachim.top/*
    // @grant        GM_setValue
    // @grant        GM_getValue
    // @grant        GM_xmlhttpRequest
    // @connect      mitmachim.top
    // @connect      otzaria.org
    // @unsafeWindow
    // @run-at       document-end
    // ==/UserScript==
    
    (function() {
        'use strict';
    
        function getForumBaseUrl() {
            const relativePath = (unsafeWindow.config && unsafeWindow.config.relative_path) || '';
            return window.location.origin + relativePath;
        }
    
        // ==========================================
        // חלק א': יצירת הפופאפ המשותף
        // ==========================================
        const sharedPopup = document.createElement('div');
        Object.assign(sharedPopup.style, {
            position: 'fixed',
            backgroundColor: '#ffffff',
            border: '1px solid #e2e8f0',
            borderRadius: '12px',
            padding: '16px',
            boxShadow: '0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)',
            zIndex: '10005',
            display: 'none',
            width: '420px',
            maxHeight: '450px',
            overflowY: 'auto',
            fontSize: '14px',
            direction: 'rtl',
            lineHeight: '1.6',
            color: '#1e293b',
            fontFamily: 'system-ui, -apple-system, sans-serif'
        });
        document.body.appendChild(sharedPopup);
    
        sharedPopup.addEventListener('click', (e) => e.stopPropagation());
        document.addEventListener('click', () => { sharedPopup.style.display = 'none'; });
    
        function positionPopup(anchorElement) {
            const rect = anchorElement.getBoundingClientRect();
            sharedPopup.style.left = `${rect.right + 15}px`;
            sharedPopup.style.top = `${Math.min(rect.top, window.innerHeight - 460)}px`;
            sharedPopup.style.display = 'block';
        }
    
        // --- פופאפ לקריאה בהמשך (פוסטים) ---
        function openReadLaterPopup(anchorElement) {
            positionPopup(anchorElement);
            const savedList = GM_getValue('saved_to_read_data', []);
    
            if (savedList.length === 0) {
                sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין פוסטים שמורים לקריאה בהמשך.</div>';
                return;
            }
    
            sharedPopup.innerHTML = `<h4 style="margin: 0 0 12px 0; font-size: 16px; font-weight: bold; border-bottom: 1px solid #e2e8f0; padding-bottom: 8px; color: #0f172a;">רשימת קריאה בהמשך (${savedList.length})</h4><div id="popup-items-container"></div>`;
            const container = sharedPopup.querySelector('#popup-items-container');
    
            savedList.forEach(item => {
                const itemWrapper = document.createElement('div');
                itemWrapper.style.cssText = 'padding: 10px; border-bottom: 1px solid #f1f5f9; margin-bottom: 8px; background: #f8fafc; border-radius: 6px; position: relative;';
    
                const fullUrl = `${getForumBaseUrl()}/post/${item.pid}`;
                itemWrapper.innerHTML = `
                    <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:4px;">
                        <a href="${fullUrl}" target="_blank" style="font-weight:600; color:#2563eb; text-decoration:none; font-size:13px; max-width:80%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">${item.title}</a>
                        <button class="delete-saved-btn" style="background:none; border:none; color:#ef4444; cursor:pointer; padding:2px 6px; font-size:12px;"><i class="fa fa-trash"></i></button>
                    </div>
                    <div style="font-size:11px; color:#64748b; margin-bottom:4px;">נכתב על ידי: <strong>${item.author}</strong></div>
                    <div style="font-size:12px; color:#334155; background:#ffffff; padding:6px; border-radius:4px; border:1px solid #e2e8f0; max-height:60px; overflow:hidden;">${item.snippet}</div>
                `;
    
                itemWrapper.querySelector('.delete-saved-btn').addEventListener('click', (e) => {
                    e.preventDefault(); e.stopPropagation();
                    let currentList = GM_getValue('saved_to_read_data', []);
                    currentList = currentList.filter(x => x.pid !== item.pid);
                    GM_setValue('saved_to_read_data', currentList);
                    itemWrapper.remove();
                    updateBadgesAndCounters();
                    if (currentList.length === 0) sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין פוסטים שמורים לקריאה בהמשך.</div>';
                });
                container.appendChild(itemWrapper);
            });
        }
    
        // --- פופאפ סימניות שלי (נושאים) ---
        function openBookmarksPopup(anchorElement) {
            positionPopup(anchorElement);
            const savedTopics = GM_getValue('saved_topics_data', []);
    
            if (savedTopics.length === 0) {
                sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין נושאים שמורים בסימניות.</div>';
                return;
            }
    
            sharedPopup.innerHTML = `<h4 style="margin: 0 0 12px 0; font-size: 16px; font-weight: bold; border-bottom: 1px solid #e2e8f0; padding-bottom: 8px; color: #0f172a;">הסימניות שלי - נושאים (${savedTopics.length})</h4><div id="popup-topics-container"></div>`;
            const container = sharedPopup.querySelector('#popup-topics-container');
    
            savedTopics.forEach(item => {
                const itemWrapper = document.createElement('div');
                itemWrapper.style.cssText = 'padding: 10px; border-bottom: 1px solid #f1f5f9; margin-bottom: 8px; background: #f8fafc; border-radius: 6px; position: relative;';
    
                const fullUrl = `${getForumBaseUrl()}/topic/${item.tid}`;
                itemWrapper.innerHTML = `
                    <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:4px;">
                        <a href="${fullUrl}" target="_blank" style="font-weight:600; color:#0284c7; text-decoration:none; font-size:13px; max-width:80%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;"><i class="fa fa-folder-open-o"></i> ${item.title}</a>
                        <button class="delete-topic-btn" style="background:none; border:none; color:#ef4444; cursor:pointer; padding:2px 6px; font-size:12px;"><i class="fa fa-trash"></i></button>
                    </div>
                    <div style="font-size:12px; color:#334155; background:#ffffff; padding:6px; border-radius:4px; border:1px solid #e2e8f0; max-height:60px; overflow:hidden;">${item.snippet}</div>
                `;
    
                itemWrapper.querySelector('.delete-topic-btn').addEventListener('click', (e) => {
                    e.preventDefault(); e.stopPropagation();
                    let currentTopics = GM_getValue('saved_topics_data', []);
                    currentTopics = currentTopics.filter(x => x.tid !== item.tid);
                    GM_setValue('saved_topics_data', currentTopics);
                    itemWrapper.remove();
                    updateBadgesAndCounters();
                    if (currentTopics.length === 0) sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין נושאים שמורים בסימניות.</div>';
                });
                container.appendChild(itemWrapper);
            });
        }
    
        // ==========================================
        // חלק ב': עדכון בועות מספרים (Badges) דינמי
        // ==========================================
        function updateBadgesAndCounters() {
            const readLaterCount = GM_getValue('saved_to_read_data', []).length;
            const bookmarksCount = GM_getValue('saved_topics_data', []).length;
    
            const rlBadge = document.getElementById('rl-count-badge');
            if (rlBadge) {
                rlBadge.textContent = readLaterCount;
                rlBadge.style.display = readLaterCount > 0 ? 'inline-block' : 'none';
            }
    
            const bmBadge = document.getElementById('bm-count-badge');
            if (bmBadge) {
                bmBadge.textContent = bookmarksCount;
                bmBadge.style.display = bookmarksCount > 0 ? 'inline-block' : 'none';
            }
        }
    
        // ==========================================
        // חלק ג': שילוב מושלם וחסין בסרגל השמאלי (מגרסה 3.4)
        // ==========================================
        function integrateIntoLeftSidebar() {
            const lists = document.querySelectorAll('#main-nav, .sidebar-nav, [component^="sidebar/"] ul, .nav-list, #menu, #user-control-list');
            let leftSidebarNav = null;
    
            lists.forEach(el => {
                const rect = el.getBoundingClientRect();
                if (rect.width > 0 && rect.left < window.innerWidth / 2) {
                    leftSidebarNav = el;
                }
            });
    
            if (!leftSidebarNav) return;
    
            if (!document.getElementById('custom-sidebar-styles')) {
                const style = document.createElement('style');
                style.id = 'custom-sidebar-styles';
                style.innerHTML = `
                    .custom-sidebar-item .nav-text {
                        display: none;
                        margin-right: 10px;
                    }
                    html.sidebar-left-open .custom-sidebar-item .nav-text,
                    body.sidebar-left-open .custom-sidebar-item .nav-text,
                    .sidebar-open .custom-sidebar-item .nav-text,
                    .open .custom-sidebar-item .nav-text,
                    #sidebar-left.open .custom-sidebar-item .nav-text {
                        display: inline-block !important;
                    }
                    .custom-badge {
                        position: absolute;
                        top: 2px;
                        left: 5px;
                        background-color: #ef4444;
                        color: white;
                        font-size: 10px;
                        font-weight: bold;
                        padding: 2px 6px;
                        border-radius: 10px;
                        min-width: 18px;
                        text-align: center;
                        line-height: 1;
                        box-shadow: 0 1px 3px rgba(0,0,0,0.2);
                    }
                    .custom-sidebar-item a {
                        position: relative;
                    }
                `;
                document.head.appendChild(style);
            }
    
            if (!document.getElementById('integrated-to-read-li')) {
                const li = document.createElement('li');
                li.id = 'integrated-to-read-li';
                li.className = 'nav-item custom-sidebar-item';
                li.innerHTML = `
                    <a class="nav-link" href="#" title="לקריאה בהמשך" style="cursor:pointer; display:flex; align-items:center; padding: 10px 15px;">
                        <i class="fa fa-fw fa-list-alt"></i>
                        <span class="nav-text">לקריאה בהמשך</span>
                        <span id="rl-count-badge" class="custom-badge unread-count badge" style="display:none;">0</span>
                    </a>
                `;
                li.querySelector('a').addEventListener('click', (e) => {
                    e.preventDefault(); e.stopPropagation();
                    openReadLaterPopup(li);
                }, true);
                leftSidebarNav.appendChild(li);
            }
    
            if (!document.getElementById('integrated-bookmarks-li')) {
                const li = document.createElement('li');
                li.id = 'integrated-bookmarks-li';
                li.className = 'nav-item custom-sidebar-item';
                li.innerHTML = `
                    <a class="nav-link" href="#" title="הסימניות שלי" style="display:flex; align-items:center; padding: 10px 15px;">
                        <i class="fa fa-fw fa-bookmark"></i>
                        <span class="nav-text">הסימניות שלי</span>
                        <span id="bm-count-badge" class="custom-badge unread-count badge" style="display:none;">0</span>
                    </a>
                `;
                li.querySelector('a').addEventListener('click', (e) => {
                    e.preventDefault(); e.stopPropagation();
                    openBookmarksPopup(li);
                }, true);
                leftSidebarNav.appendChild(li);
            }
    
            updateBadgesAndCounters();
        }
    
        // ==========================================
        // חלק ד': הזרקת כפתור סימנייה לסרגל הכלים הראשי של הנושא
        // ==========================================
        function enhanceTopicHeaderTools() {
            if (document.getElementById('top-bar-save-topic-btn')) return;
    
            const currentTid = (unsafeWindow.ajaxify && unsafeWindow.ajaxify.data && unsafeWindow.ajaxify.data.tid) || null;
            if (!currentTid) return;
    
            const exportBtn = document.querySelector('.fa-download')?.closest('a, button');
            if (!exportBtn) return;
    
            const parentContainer = exportBtn.parentElement;
            if (!parentContainer) return;
    
            const topicTitle = document.querySelector('[component="topic/title"]')?.textContent.trim() || 'נושא בפורום';
    
            const topicBtn = document.createElement('button');
            topicBtn.id = 'top-bar-save-topic-btn';
    
            topicBtn.className = exportBtn.className || 'btn btn-sm btn-link text-secondary text-body';
            topicBtn.style.cssText = 'cursor: pointer; display: inline-flex; align-items: center; gap: 8px; text-decoration: none; background: none; border: none; margin-left: 12px;';
    
            let savedTopics = GM_getValue('saved_topics_data', []);
            const isTopicSaved = savedTopics.some(x => x.tid === currentTid);
            topicBtn.innerHTML = `<i class="fa ${isTopicSaved ? 'fa-folder' : 'fa-folder-o'}"></i> <span>שמור כסימניה</span>`;
    
            topicBtn.addEventListener('click', (e) => {
                e.preventDefault();
                let currentTopics = GM_getValue('saved_topics_data', []);
                const icon = topicBtn.querySelector('i');
    
                if (currentTopics.some(x => x.tid === currentTid)) {
                    currentTopics = currentTopics.filter(x => x.tid !== currentTid);
                    icon.className = 'fa fa-folder-o';
                } else {
                    const firstPostEl = document.querySelector('[component="post"] .content, [component="post/content"]');
                    let snippet = firstPostEl ? firstPostEl.textContent.trim().substring(0, 120) : 'לחץ למעבר לצפייה בנושא המלא...';
                    if (snippet.length >= 120) snippet += '...';
    
                    currentTopics.push({
                        tid: currentTid,
                        title: topicTitle,
                        snippet: snippet
                    });
                    icon.className = 'fa fa-folder';
                }
                GM_setValue('saved_topics_data', currentTopics);
                updateBadgesAndCounters();
            });
    
            parentContainer.insertBefore(topicBtn, exportBtn);
        }
    
        // ==========================================
        // חלק ה': הזרקת כפתורים לפוסטים (צ'אט אוטומטי מלא)
        // ==========================================
        function enhancePosts() {
            const posts = document.querySelectorAll('[component="post"]:not(.enhanced-post)');
            const topicTitle = document.querySelector('[component="topic/title"]')?.textContent.trim() || 'נושא בפורום';
    
            posts.forEach(post => {
                post.classList.add('enhanced-post');
                const tools = post.querySelector('.post-tools, [component="post/tools"], [component="post/actions"]');
                if (!tools) return;
    
                const pid = post.getAttribute('data-pid');
                const postUid = post.getAttribute('data-uid');
                const authorName = post.getAttribute('data-username') || 'משתמש';
                const currentUid = (unsafeWindow.app && unsafeWindow.app.user) ? unsafeWindow.app.user.uid : null;
    
                // 1. כפתור צ'אט אוטומטי חסין (הדמיית Mouseenter והזרקת קישור)
                if (postUid && currentUid && Array.of(0, currentUid).includes(Number(postUid)) === false && !tools.querySelector('.custom-chat-btn')) {
                    const chatBtn = document.createElement('a');
                    chatBtn.className = 'btn btn-xs btn-link custom-chat-btn';
                    chatBtn.innerHTML = '<i class="fa fa-fw fa-comment-dots"></i> צ\'אט';
                    chatBtn.style.marginLeft = '8px';
                    chatBtn.style.cursor = 'pointer';
    
                    chatBtn.addEventListener('click', async function (e) {
                        e.preventDefault();
                        e.stopPropagation();
    
                        const userLink = post.querySelector('a[data-uid]');
                        if (!userLink) return;
    
                        userLink.dispatchEvent(new PointerEvent('pointerenter', { bubbles: true }));
                        userLink.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
                        userLink.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
    
                        const observer = new MutationObserver(() => {
                            const popoverId = userLink.getAttribute('aria-describedby');
                            if (!popoverId) return;
    
                            const popover = document.getElementById(popoverId);
                            if (!popover) return;
    
                            const btn =
                                popover.querySelector('[component="account/new-chat"]') ||
                                popover.querySelector('[component="account/chat"]') ||
                                popover.querySelector('a[href*="/chats"]');
    
                            if (btn) {
                                observer.disconnect();
    
                                const postUrl = pid ? `${getForumBaseUrl()}/post/${pid}` : window.location.href;
    
                                const chatInputObserver = new MutationObserver(() => {
                                    const chatInput = document.querySelector('[component="chat/input"]') || document.querySelector('.chat-input');
    
                                    if (chatInput) {
                                        chatInputObserver.disconnect();
    
                                        if (!chatInput.value.includes(postUrl)) {
                                            chatInput.value = postUrl + '\n' + chatInput.value;
                                            chatInput.dispatchEvent(new Event('input', { bubbles: true }));
                                            chatInput.dispatchEvent(new Event('change', { bubbles: true }));
                                            chatInput.focus();
                                        }
                                    }
                                });
    
                                chatInputObserver.observe(document.body, { childList: true, subtree: true });
                                setTimeout(() => chatInputObserver.disconnect(), 5000);
    
                                btn.click();
                            }
                        });
    
                        observer.observe(document.body, { childList: true, subtree: true });
                        setTimeout(() => observer.disconnect(), 5000);
                    });
    
                    tools.appendChild(chatBtn);
                }
    
                // 2. כפתור שמור לקריאה (פוסטים)
                if (pid && !tools.querySelector('.custom-save-read-btn')) {
                    const saveBtn = document.createElement('button');
                    saveBtn.className = 'btn btn-xs btn-link custom-save-read-btn';
                    saveBtn.style.marginLeft = '8px';
    
                    let savedList = GM_getValue('saved_to_read_data', []);
                    const isSaved = savedList.some(x => x.pid === pid);
                    saveBtn.innerHTML = `<i class="fa ${isSaved ? 'fa-bookmark' : 'fa-bookmark-o'}"></i> לקריאה בהמשך`;
    
                    saveBtn.addEventListener('click', (e) => {
                        e.preventDefault();
                        let currentList = GM_getValue('saved_to_read_data', []);
                        if (currentList.some(x => x.pid === pid)) {
                            currentList = currentList.filter(x => x.pid !== pid);
                            saveBtn.querySelector('i').className = 'fa fa-bookmark-o';
                        } else {
                            const contentEl = post.querySelector('.content') || post.querySelector('[component="post/content"]');
                            let snippet = contentEl ? contentEl.textContent.trim().substring(0, 120) : '';
                            if (snippet.length >= 120) snippet += '...';
    
                            currentList.push({
                                pid: pid,
                                title: topicTitle,
                                author: authorName,
                                snippet: snippet
                            });
                            saveBtn.querySelector('i').className = 'fa fa-bookmark';
                        }
                        GM_setValue('saved_to_read_data', currentList);
                        updateBadgesAndCounters();
                    });
                    tools.appendChild(saveBtn);
                }
    
                // 3. כפתור העתקת קישור מדויק לפוסט
                if (pid && !tools.querySelector('.custom-copy-link-btn')) {
                    const copyBtn = document.createElement('button');
                    copyBtn.className = 'btn btn-xs btn-link custom-copy-link-btn';
                    copyBtn.style.marginLeft = '8px';
                    copyBtn.innerHTML = '<i class="fa fa-copy"></i> העתק קישור';
    
                    copyBtn.addEventListener('click', (e) => {
                        e.preventDefault();
                        const postUrl = `${getForumBaseUrl()}/post/${pid}`;
                        navigator.clipboard.writeText(postUrl);
                    });
                    tools.appendChild(copyBtn);
                }
            });
        }
    
        // ==========================================
        // חלק ו': תצוגה מקדימה של פוסטים באזורי צ'אט
        // ==========================================
        const previewPopup = document.createElement('div');
        Object.assign(previewPopup.style, {
            position: 'absolute',
            backgroundColor: '#ffffff',
            border: '1px solid #dddddd',
            borderRadius: '8px',
            padding: '12px',
            boxShadow: '0 4px 15px rgba(0,0,0,0.15)',
            zIndex: '10000',
            display: 'none',
            maxWidth: '400px',
            maxHeight: '300px',
            overflowY: 'auto',
            fontSize: '14px',
            direction: 'rtl',
            lineHeight: '1.5',
            color: '#333333'
        });
        document.body.appendChild(previewPopup);
    
        let activeRequest = null;
        let hideTimeout = null;
    
        previewPopup.addEventListener('mouseenter', () => { clearTimeout(hideTimeout); });
        previewPopup.addEventListener('mouseleave', () => { previewPopup.style.display = 'none'; });
    
        function isInsideChat(link) {
            const path = window.location.pathname;
            if (path.includes('/chats') || /\/user\/[^/]+\/chats/.test(path)) return true;
            return !!link.closest('[component^="chat"]') ||
                   !!link.closest('.chat-window') ||
                   !!link.closest('.chat-modal') ||
                   !!link.closest('.chat-messages') ||
                   !!link.closest('.chat-content') ||
                   !!link.closest('.expanded-chat');
        }
    
        function fetchPostContent(fullUrl, pid) {
            return new Promise((resolve) => {
                if (activeRequest) {
                    try { activeRequest.abort(); } catch(e){}
                }
    
                activeRequest = GM_xmlhttpRequest({
                    method: "GET",
                    url: fullUrl,
                    onload: function(response) {
                        try {
                            const parser = new DOMParser();
                            const doc = parser.parseFromString(response.responseText, 'text/html');
                            const postContainer = doc.querySelector(`[data-pid="${pid}"]`);
    
                            let contentEl = null;
                            let authorEl = null;
                            let avatarEl = null;
    
                            if (postContainer) {
                                contentEl = postContainer.querySelector('.content') ||
                                            postContainer.querySelector('[component="post/content"]') ||
                                            postContainer.querySelector('.post-content');
    
                                authorEl = postContainer.querySelector('[component="post/author"]') ||
                                           postContainer.querySelector('.username') ||
                                           postContainer.querySelector('[component="user/username"]') ||
                                           postContainer.querySelector('.author-name') ||
                                           postContainer.querySelector('[data-username]');
    
                                avatarEl = postContainer.querySelector('.avatar') ||
                                           postContainer.querySelector('[component="user/picture"]') ||
                                           postContainer.querySelector('.user-img') ||
                                           postContainer.querySelector('.author-avatar') ||
                                           postContainer.querySelector('.avatar-wrapper');
                            } else {
                                contentEl = doc.querySelector('.content') || doc.querySelector('[component="post/content"]');
                                authorEl = doc.querySelector('.username') || doc.querySelector('[component="post/author"]');
                                avatarEl = doc.querySelector('.avatar') || doc.querySelector('[component="user/picture"]');
                            }
    
                            let avatarHtml = '';
                            if (avatarEl) {
                                const clone = avatarEl.cloneNode(true);
                                clone.style.width = '24px';
                                clone.style.height = '24px';
                                clone.style.borderRadius = '50%';
                                clone.style.marginLeft = '8px';
                                clone.style.display = 'inline-block';
                                clone.style.verticalAlign = 'middle';
                                clone.style.objectFit = 'cover';
                                clone.style.lineHeight = '24px';
                                clone.style.fontSize = '11px';
                                avatarHtml = clone.outerHTML;
                            }
    
                            resolve({
                                content: contentEl ? contentEl.innerHTML : 'לא ניתן ליצור תצוגה מקדימה של הפוסט כרגע.',
                                author: authorEl ? (authorEl.getAttribute('data-username') || authorEl.textContent.trim()) : 'משתמש',
                                avatarHtml: avatarHtml
                            });
                        } catch(e) {
                            resolve({ content: 'שגיאה בפענוח התצוגה המקדימה.', author: 'מערכת', avatarHtml: '' });
                        }
                    },
                    onerror: function() {
                        resolve({ content: 'שגיאה בטעינת התצוגה המקדימה.', author: 'מערכת', avatarHtml: '' });
                    }
                });
            });
        }
    
        document.body.addEventListener('mouseover', async (e) => {
            const link = e.target.closest('a[href*="/post/"]');
            if (!link || !isInsideChat(link)) return;
    
            const match = link.href.match(/(mitmachim\.top|otzaria\.org).*?\/post\/(\d+)/);
            if (!match) return;
    
            clearTimeout(hideTimeout);
    
            const pid = match[2];
            const fullUrl = link.href;
    
            const rect = link.getBoundingClientRect();
            previewPopup.style.left = `${rect.left + window.scrollX}px`;
            previewPopup.style.top = `${rect.bottom + window.scrollY + 8}px`;
            previewPopup.innerHTML = '<i class="fa fa-spinner fa-spin"></i> טוען תצוגה מקדימה...';
            previewPopup.style.display = 'block';
    
            const data = await fetchPostContent(fullUrl, pid);
            if (!data) return;
    
            previewPopup.innerHTML = `
                <div style="font-weight: bold; color: #007bff; margin-bottom: 8px; display: flex; align-items: center;">
                    ${data.avatarHtml || '<i class="fa fa-user" style="margin-left: 8px;"></i>'}
                    <span>${data.author}:</span>
                </div>
                <div class="post-preview-body">${data.content}</div>
            `;
        });
    
        document.body.addEventListener('mouseout', (e) => {
            const link = e.target.closest('a[href*="/post/"]');
            if (link && isInsideChat(link)) {
                hideTimeout = setTimeout(() => {
                    if (activeRequest) {
                        try { activeRequest.abort(); } catch(e){}
                    }
                    previewPopup.style.display = 'none';
                }, 300);
            }
        });
    
        // ==========================================
        // הפעלה מבוקרת ללא עומס DOM
        // ==========================================
        enhancePosts();
        enhanceTopicHeaderTools();
        integrateIntoLeftSidebar();
    
        let debounceTimer;
        const domObserver = new MutationObserver(() => {
            clearTimeout(debounceTimer);
            debounceTimer = setTimeout(() => {
                enhancePosts();
                enhanceTopicHeaderTools();
                integrateIntoLeftSidebar();
            }, 100);
        });
        domObserver.observe(document.body, { childList: true, subtree: true });
    })();
    

    עודכן לגרסה 4.9

    @צדיק-וטוב-לו-0
    @ע-ה-דכו-ע
    @לאצי

    באגים/הצעות ייעול

  • מדריך | הוספת שורה בהגדרות> אפ' והתראות של התראות חירום
    מחנה ידידיםמ מחנה ידידים

    הכנסו באפליקציית ההגדרות דרך מנהל MT לres/xml/app_and_notification.xml

    והוסיפו את השורה הזו:

        <Preference
            android:title="התרעות חירום אלחוטיות"
            android:key="my_custom_emergency_alerts_key"
            android:summary="ניהול התראות במצבי חירום, איומים ובדיקות מערכת"
            android:order="15">
            <intent
                android:targetPackage="****"
                android:action="****"
                android:targetClass="****" />
        </Preference>
    

    החליפו את הכוכביות הראשונות בשם החבילה ואת השניות והשלישיות באקטיביטי של התפריט

    בדרך כלל שם החבילה הוא:

    com.mediatek.cellbroadcastreceiver.module
    

    והאקטיביטי:

     com.mediatek.cellbroadcastreceiver.module.CellBroadcastSettings
    

    ㅤ

    ㅤ

    אם תרצו שבאנגלית השורה תהיה באנגלית תצטרכו להוסיף סטרינג.

    הכנסו בMT לקובץ resources.arsc בעורך arsc. לחצו על השורה התחתונה, הכנסו לstring ושוב לstring. לחצו בתפריט הצדדי על "הוסף" והדביקו שם:

    emergency_alerts_title
    

    זכרו את מזהה הכניסה.
    לחצו על הסטרינג, בשורה "תוכן" הכניסו Wireless emergency Alerts.

    צאו מstring, הכנסו לstring-iw ולחצו שוב על "הוסף". הכניסו את מזהה הכניסה של הסטרינג הקודם - והשם יהפך אוטומטית לemergency_alerts_title.
    לחצו על הסטרינג, בשורה "תוכן" הכניסו התרעות חירום אלחוטיות.

    אותו הדבר לסטרינג הsummary. רק שלו קוראים

    emergency_alerts_summary
    

    והתוכן הוא ניהול התראות במצבי חירום, איומים ובדיקות מערכת
    ובאנגלית Emergency alerts management

    עכשיו שימו במקום הטקסט הקודם את זה:

        <Preference
            android:title="@string/emergency_alerts_title"
            android:key="my_custom_emergency_alerts_key"
            android:summary="@string/emergency_alerts_summary"
            android:order="15">
            <intent
                android:targetPackage="****"
                android:action="****"
                android:targetClass="****" />
        </Preference>
    
    מדריכים -שיאומי f21 pro ו +f21 pro

  • שיתוף | לאונצ'ר תומך מקשים שיצרתי!
    מחנה ידידיםמ מחנה ידידים

    Screenshot_20260603-183552.png

    הגרסה הראשונית:

    nokia-launcher.apk

    גרסה עם הפונט של נוקיה:

    nokia-hebrew.apk

    לשיאומי מקשים:

    nokia-hebrew.apk

    תוצרת הבנייה

  • שיתוף | לאונצ'ר פשוט דמוי מכשירי mocor os
    מחנה ידידיםמ מחנה ידידים

    לאונצ'ר עם מערכת דמוית מכשירי קיוליקס, פותח עבור לקוח שעבר מQ8 ל f21 pro.

    Screenshot_20260831-100907.png Screenshot_20260831-095751.png

    סקירה מאת קלוד:

    # Key Launcher — לאנצ'ר לניווט במקשים (עם תמיכה מלאה במגע)

    מה זה?

    Key Launcher הוא לאנצ'ר (מסך בית) לאנדרואיד שנבנה מהיסוד לשימוש נוח במקשים פיזיים — D-Pad, מקשי בחירה (Soft Left/Right), Back, מקש מרכזי — בדיוק כמו בפיצ'ר-פונים הישנים והטובים, אבל עם כל מה שאנדרואיד מודרני יודע לעשות. מגע נתמך באופן מלא כאפשרות משנית, אז זה עובד מצוין גם על מסך רגיל ללא מקשים.

    נכתב כולו ב-Kotlin, בלי שום תלות בספריות AndroidX/Jetpack — רק framework אנדרואיד טהור. תומך מ-Android 4.4 (KitKat) ועד Android 14.

    המסכים

    מסך הבית

    • שעון דיגיטלי גדול (עם הקו המפריד המלא), תאריך לועזי ותאריך עברי מלא (כולל גימטריה — "ט"ו אלול תשפ"ו" וכו')
    • סטטוס כרטיס סים (כולל תמיכה ב-Dual SIM)
    • מציג את הטפט האמיתי של המכשיר ברקע, כמו בכל לאנצ'ר
    • כל הטקסטים לבנים עם מסגרת שחורה — קריאים על כל טפט, בהיר או כהה

    דף קיצורים — רשת 3x2 של עד 6 אפליקציות נבחרות, עם כותרת פוקוס דינמית שמראה איזה אייקון ממוקד כרגע

    דף התפריט (App Drawer) — כל האפליקציות המותקנות, ברשת 3x3, עם גלילה מעגלית בין "עמודים"

    מסך "נהל" — בחירת אילו אפליקציות מופיעות בדף הקיצורים (עד 6), עם רשימה גוללת וצ'קבוקסים

    מסך "סדר" — סידור מחדש של האייקונים במנגנון "הרם-הזז-הנח" (Pick-up / Move / Drop), נשלט לגמרי דרך המקלדת

    עיצוב

    פלטת צבעים עקבית בכל האפליקציה — רקע שמנת חם (#F5EFE3), אייקונים בגרדיאנט כחול, הדגשות פוקוס כחולות ברורות, וטיפוגרפיה מותאמת עברית עם תמיכת RTL מלאה בכל מסך ומסך.

    תאימות טכנית

    • Kotlin, ללא AndroidX — framework אנדרואיד טהור בלבד
    • minSdk 19 (KitKat) עד targetSdk 34
    • טעינת אייקונים עם caching לביצועים טובים גם על מכשירים חלשים
    • תאריך עברי: android.icu.util.HebrewCalendar ב-API 24+, עם אלגוריתם ידני (Dershowitz-Reingold) לגרסאות ישנות יותר

    מצב נוכחי

    עדיין בפיתוח פעיל ובבדיקות על מכשיר אמיתי (כולל מכשיר היברידי מקשים+מגע) — יש עוד כמה דברים לחדד. שמח לקבל פידבק, דיווחי באגים, והצעות!

    האפליקציה להורדה:

    KeyLauncher-sign.apk

    אמור לתמוך בשיאומי מקשים
    @יאיר-דניאל @חייא-שיאומי

    תוצרת הבנייה

  • מדריך | הוספת תאריך עברי למסך הנעילה בf21 pro
    מחנה ידידיםמ מחנה ידידים

     

    נבדק על ידי ועובד. מי שרוצה שאצור גם לf22 pro שידבר איתי.

    המדריך דורש:

    רוט - תעשו אם אין לכם
    מנהל MT - מנהל-MT-מתורגם.apk


    שלב 1: יצירת מחלקות הלוגיקה.

    בתוך MT Manager, פתח את com.android.systemui, כנס ל-classes.dex (ב-Dex Editor Plus) וצור שני קבצים בנתיב /com/android/systemui:

    1. HebrewDateHelper.smali
    קובץ זה מחשב את השקיעה לפי הנוסחה המתמטית (Sin/Cos) ומפיק את הטקסט "מוצאי שבת" או "אור ל-".

    .class public Lcom/android/systemui/HebrewDateHelper;
    .super Ljava/lang/Object;
    
    # --- מתודה ראשית לעדכון ה-TextView ---
    .method public static updateHebrewDisplay(Landroid/widget/TextView;)V
        .registers 2
        if-nez p0, :cond_3
        return-void
        :cond_3
        invoke-static {}, Lcom/android/systemui/HebrewDateHelper;->getSmartDate()Ljava/lang/String;
        move-result-object v0
        invoke-virtual {p0, v0}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
        return-void
    .end method
    
    # --- לוגיקה חכמה לבחירת הנוסח ---
    .method public static getSmartDate()Ljava/lang/String;
        .registers 4
        # בדיקה האם עכשיו לילה לפי החישוב המתמטי
        invoke-static {}, Lcom/android/systemui/HebrewDateHelper;->isAfterNightfall()Z
        move-result v0
        
        # יצירת לוח שנה עברי (ICU)
        new-instance v1, Landroid/icu/util/HebrewCalendar;
        invoke-direct {v1}, Landroid/icu/util/HebrewCalendar;-><init>()V
    
        if-eqz v0, :cond_30 # אם לילה
        
        # בדיקה אם יום שבת (7 ב-Calendar)
        const/4 v2, 0x7 
        invoke-virtual {v1, v2}, Landroid/icu/util/HebrewCalendar;->get(I)I
        move-result v3
        
        if-ne v3, v2, :cond_20
        const-string v0, "מוצאי שבת"
        return-object v0
    
        :cond_20
        # אם לילה ואינו מוצ"ש - הוסף יום (מעבר לתאריך של מחר) והוסף "אור ל-"
        const/4 v2, 0x5 # DATE
        const/4 v3, 0x1
        invoke-virtual {v1, v2, v3}, Landroid/icu/util/HebrewCalendar;->add(II)V
        
        new-instance v0, Ljava/lang/StringBuilder;
        invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
        const-string v2, "אור ל-"
        invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
        invoke-static {v1}, Lcom/android/systemui/HebrewDateHelper;->formatHebrew(Landroid/icu/util/HebrewCalendar;)Ljava/lang/String;
        move-result-object v1
        invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
        invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
        move-result-object v0
        return-object v0
    
        :cond_30 # אם יום (לפני שקיעה)
        invoke-static {v1}, Lcom/android/systemui/HebrewDateHelper;->formatHebrew(Landroid/icu/util/HebrewCalendar;)Ljava/lang/String;
        move-result-object v0
        return-object v0
    .end method
    
    # --- פורמט התאריך העברי (ICU) ---
    .method private static formatHebrew(Landroid/icu/util/HebrewCalendar;)Ljava/lang/String;
        .registers 4
        new-instance v0, Landroid/icu/util/ULocale;
        const-string v1, "he_IL@calendar=hebrew"
        invoke-direct {v0, v1}, Landroid/icu/util/ULocale;-><init>(Ljava/lang/String;)V
        
        const/4 v1, 0x0 # LONG style
        invoke-static {v1, v0}, Landroid/icu/text/DateFormat;->getDateInstance(ILandroid/icu/util/ULocale;)Landroid/icu/text/DateFormat;
        move-result-object v0
        
        invoke-virtual {p0}, Landroid/icu/util/HebrewCalendar;->getTime()Ljava/util/Date;
        move-result-object v1
        invoke-virtual {v0, v1}, Landroid/icu/text/DateFormat;->format(Ljava/util/Date;)Ljava/lang/String;
        move-result-object v0
        return-object v0
    .end method
    
    # --- חישוב שקיעה מתמטי (Sin/Cos) ---
    .method private static isAfterNightfall()Z
        .registers 10
        invoke-static {}, Ljava/util/Calendar;->getInstance()Ljava/util/Calendar;
        move-result-object v0
        
        # קבלת נתוני הזמן הנוכחיים
        const/4 v1, 0x6 # DAY_OF_YEAR
        invoke-virtual {v0, v1}, Ljava/util/Calendar;->get(I)I
        move-result v1
        const/16 v2, 0xb # HOUR_OF_DAY
        invoke-virtual {v0, v2}, Ljava/util/Calendar;->get(I)I
        move-result v2
        const/16 v3, 0xc # MINUTE
        invoke-virtual {v0, v3}, Ljava/util/Calendar;->get(I)I
        move-result v3
    
        # חישוב שעת שקיעה משוערת
        const-wide v4, 0x400921fb54442d18L # 2 * PI
        const-wide/high16 v6, 0x4000000000000000L # 2.0
        mul-double/2addr v4, v6
        add-int/lit8 v6, v1, -0x50
        int-to-double v6, v6
        mul-double/2addr v4, v6
        const-wide v6, 0x4076d00000000000L # 365.0
        div-double/2addr v4, v6
        invoke-static {v4, v5}, Ljava/lang/Math;->sin(D)D
        move-result-wide v4
        
        const-wide v6, 0x3ff0cccccccccccdL # 1.05
        mul-double/2addr v4, v6
        const-wide v6, 0x403247ae147ae148L # 18.28 (שעה בסיסית לשקיעה)
        add-double/2addr v4, v6
    
        # בדיקת שעון קיץ ועדכון השעה
        invoke-virtual {v0}, Ljava/util/Calendar;->getTimeZone()Ljava/util/TimeZone;
        move-result-object v6
        invoke-virtual {v0}, Ljava/util/Calendar;->getTime()Ljava/util/Date;
        move-result-object v0
        invoke-virtual {v6, v0}, Ljava/util/TimeZone;->inDaylightTime(Ljava/util/Date;)Z
        move-result v0
        if-eqz v0, :cond_52
        const-wide/high16 v6, 0x3ff0000000000000L # +1.0
        add-double/2addr v4, v6
    
        :cond_52
        # המרת התוצאה לשעות ודקות
        double-to-int v0, v4 # שעת שקיעה
        int-to-double v6, v0
        sub-double/2addr v4, v6
        const-wide v6, 0x404e000000000000L # 60.0
        mul-double/2addr v4, v6
        double-to-int v4, v4 # דקות שקיעה
    
        # השוואה לזמן אמת
        const/4 v5, 0x1
        if-le v2, v0, :cond_62
        return v5
        :cond_62
        if-ne v2, v0, :cond_67
        if-lt v3, v4, :cond_67
        return v5
        :cond_67
        const/4 v0, 0x0
        return v0
    .end method
    

    מי שרוצה ללא הצגת היום שייקח את הקוד שבספויילר:

    .class public Lcom/android/systemui/HebrewDateHelper;
    .super Ljava/lang/Object;
    
    # --- מתודה ראשית לעדכון ה-TextView ---
    .method public static updateHebrewDisplay(Landroid/widget/TextView;)V
        .registers 2
        if-nez p0, :cond_3
        return-void
        :cond_3
        invoke-static {}, Lcom/android/systemui/HebrewDateHelper;->getSmartDate()Ljava/lang/String;
        move-result-object v0
        invoke-virtual {p0, v0}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
        return-void
    .end method
    
    # --- לוגיקה חכמה לבחירת הנוסח (יום/לילה/מוצ"ש) ---
    .method public static getSmartDate()Ljava/lang/String;
        .registers 4
        invoke-static {}, Lcom/android/systemui/HebrewDateHelper;->isAfterNightfall()Z
        move-result v0
        
        new-instance v1, Landroid/icu/util/HebrewCalendar;
        invoke-direct {v1}, Landroid/icu/util/HebrewCalendar;-><init>()V
    
        if-eqz v0, :cond_30 # אם לילה (אחרי שקיעה)
        
        const/4 v2, 0x7 # יום שבת ב-Calendar
        invoke-virtual {v1, v2}, Landroid/icu/util/HebrewCalendar;->get(I)I
        move-result v3
        
        if-ne v3, v2, :cond_20
        const-string v0, "מוצאי שבת"
        return-object v0
    
        :cond_20
        # אם לילה ואינו מוצ"ש - הוספת יום והוספת "אור ל-"
        const/4 v2, 0x5 # DATE
        const/4 v3, 0x1
        invoke-virtual {v1, v2, v3}, Landroid/icu/util/HebrewCalendar;->add(II)V
        
        new-instance v0, Ljava/lang/StringBuilder;
        invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
        const-string v2, "אור ל-"
        invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
        invoke-static {v1}, Lcom/android/systemui/HebrewDateHelper;->formatHebrew(Landroid/icu/util/HebrewCalendar;)Ljava/lang/String;
        move-result-object v1
        invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
        invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
        move-result-object v0
        return-object v0
    
        :cond_30 # אם יום (לפני שקיעה)
        invoke-static {v1}, Lcom/android/systemui/HebrewDateHelper;->formatHebrew(Landroid/icu/util/HebrewCalendar;)Ljava/lang/String;
        move-result-object v0
        return-object v0
    .end method
    
    # --- פורמט התאריך העברי ללא יום בשבוע (MEDIUM style) ---
    .method private static formatHebrew(Landroid/icu/util/HebrewCalendar;)Ljava/lang/String;
        .registers 4
        new-instance v0, Landroid/icu/util/ULocale;
        const-string v1, "he_IL@calendar=hebrew"
        invoke-direct {v0, v1}, Landroid/icu/util/ULocale;-><init>(Ljava/lang/String;)V
        
        # ערך 2 מייצג MEDIUM (תאריך בלבד) במקום 0 (LONG - הכולל יום)
        const/4 v1, 0x2 
        invoke-static {v1, v0}, Landroid/icu/text/DateFormat;->getDateInstance(ILandroid/icu/util/ULocale;)Landroid/icu/text/DateFormat;
        move-result-object v0
        
        invoke-virtual {p0}, Landroid/icu/util/HebrewCalendar;->getTime()Ljava/util/Date;
        move-result-object v1
        invoke-virtual {v0, v1}, Landroid/icu/text/DateFormat;->format(Ljava/util/Date;)Ljava/lang/String;
        move-result-object v0
        return-object v0
    .end method
    
    # --- חישוב שקיעה מתמטי משוער ---
    .method private static isAfterNightfall()Z
        .registers 10
        invoke-static {}, Ljava/util/Calendar;->getInstance()Ljava/util/Calendar;
        move-result-object v0
        
        const/4 v1, 0x6 # DAY_OF_YEAR
        invoke-virtual {v0, v1}, Ljava/util/Calendar;->get(I)I
        move-result v1
        const/16 v2, 0xb # HOUR_OF_DAY
        invoke-virtual {v0, v2}, Ljava/util/Calendar;->get(I)I
        move-result v2
        const/16 v3, 0xc # MINUTE
        invoke-virtual {v0, v3}, Ljava/util/Calendar;->get(I)I
        move-result v3
    
        # חישוב גלי סינוס לקירוב שעת שקיעה לאורך השנה
        const-wide v4, 0x400921fb54442d18L # 2 * PI
        const-wide/high16 v6, 0x4000000000000000L # 2.0
        mul-double/2addr v4, v6
        add-int/lit8 v6, v1, -0x50
        int-to-double v6, v6
        mul-double/2addr v4, v6
        const-wide v6, 0x4076d00000000000L # 365.0
        div-double/2addr v4, v6
        invoke-static {v4, v5}, Ljava/lang/Math;->sin(D)D
        move-result-wide v4
        
        const-wide v6, 0x3ff0cccccccccccdL # 1.05
        mul-double/2addr v4, v6
        const-wide v6, 0x403247ae147ae148L # 18.28 (שעה בסיסית לשקיעה)
        add-double/2addr v4, v6
    
        # בדיקת שעון קיץ
        invoke-virtual {v0}, Ljava/util/Calendar;->getTimeZone()Ljava/util/TimeZone;
        move-result-object v6
        invoke-virtual {v0}, Ljava/util/Calendar;->getTime()Ljava/util/Date;
        move-result-object v0
        invoke-virtual {v6, v0}, Ljava/util/TimeZone;->inDaylightTime(Ljava/util/Date;)Z
        move-result v0
        if-eqz v0, :cond_52
        const-wide/high16 v6, 0x3ff0000000000000L # +1.0
        add-double/2addr v4, v6
    
        :cond_52
        double-to-int v0, v4 # שעות
        int-to-double v6, v0
        sub-double/2addr v4, v6
        const-wide v6, 0x404e000000000000L # 60.0
        mul-double/2addr v4, v6
        double-to-int v4, v4 # דקות
    
        const/4 v5, 0x1
        if-le v2, v0, :cond_62
        return v5
        :cond_62
        if-ne v2, v0, :cond_67
        if-lt v3, v4, :cond_67
        return v5
        :cond_67
        const/4 v0, 0x0
        return v0
    .end method
    

     

    2. HebrewDateReceiver.smali
    קובץ זה "מקשיב" למערכת ומעדכן את התצוגה.

    .class public Lcom/android/systemui/HebrewDateReceiver;
    .super Landroid/content/BroadcastReceiver;
    .field private mView:Landroid/widget/TextView;
    
    .method public constructor <init>(Landroid/widget/TextView;)V
        .registers 2
        invoke-direct {p0}, Landroid/content/BroadcastReceiver;-><init>()V
        iput-object p1, p0, Lcom/android/systemui/HebrewDateReceiver;->mView:Landroid/widget/TextView;
        return-void
    .end method
    
    .method public onReceive(Landroid/content/Context;Landroid/content/Intent;)V
        .registers 4
        iget-object v0, p0, Lcom/android/systemui/HebrewDateReceiver;->mView:Landroid/widget/TextView;
        invoke-static {v0}, Lcom/android/systemui/HebrewDateHelper;->updateHebrewDisplay(Landroid/widget/TextView;)V
        return-void
    .end method
    

    שלב 2: הגדרת התצוגה

    1. הוספת מזהה (ID):   כנס ל-resources.arsc -> Arsc Editor -> com.android.systemui > id

    2. כעת תראה רשימה ארוכה של שמות. לחץ על כפתור התפריט (3 נקודות) ובחר Add.

    3. בתיבה שנפתחת, בשדה Name, רשום בדיוק: hebrew_date_display.

    4. לחץ על אישור. יינתן ל id מספר (Hex) באופן אוטומטי. העתק את המספר הזה!
      (הוא נראה בערך ככה: 0x7f0a0123).

    5. צא חזרה ולחץ על Save כדי לשמור את השינויים בקובץ ה-arsc.

    6. הוספת האלמנט: בנתיב /res/layout, פתח את הקובץ האחראי על מסך הנעילה (keyguard_status_view.xml) והוסף:

      <TextView 
          android:id="@id/hebrew_date_display" 
          android:layout_width="match_parent" 
          android:layout_height="wrap_content" 
          android:gravity="center"
          android:layout_gravity="center_horizontal"
          android:textColor="#FFFFFF" 
          android:textSize="16sp" 
          android:layout_marginTop="4dp" />
      

    שלב 3: הזרקת הרישום לעדכון בשקיעה.

    כדי שהתאריך יבדוק כל דקה אם הגיעה השקיעה, נזריק את ה-Receiver לתוך המחלקה של מסך הנעילה (KeyguardStatusView.smali) בתוך המתודה onAttachedToWindow:

    שימו לב לעדכן את ה- ID!

    # 1. מציאת ה-View (החלף את ה-ID בערך ה-Hex ש-MT נותן לך)
    const v0, 0x7fXXXXXX 
    invoke-virtual {p0, v0}, Landroid/view/View;->findViewById(I)Landroid/view/View;
    move-result-object v0
    check-cast v0, Landroid/widget/TextView;
    
    # 2. יצירת ה-Receiver והפילטר
    new-instance v1, Lcom/android/systemui/HebrewDateReceiver;
    invoke-direct {v1, v0}, Lcom/android/systemui/HebrewDateReceiver;-><init>(Landroid/widget/TextView;)V
    new-instance v2, Landroid/content/IntentFilter;
    invoke-direct {v2}, Landroid/content/IntentFilter;-><init>()V
    
    # 3. הוספת הפעולות (כולל TICK לעדכון בשקיעה)
    const-string v3, "android.intent.action.TIME_TICK" # עדכון כל דקה לבדיקת שקיעה
    invoke-virtual {v2, v3}, Landroid/content/IntentFilter;->addAction(Ljava/lang/String;)V
    const-string v3, "android.intent.action.DATE_CHANGED"
    invoke-virtual {v2, v3}, Landroid/content/IntentFilter;->addAction(Ljava/lang/String;)V
    
    # 4. רישום בפועל
    invoke-virtual {p0}, Landroid/view/View;->getContext()Landroid/content/Context;
    move-result-object v3
    invoke-virtual {v3, v1, v2}, Landroid/content/Context;->registerReceiver(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;
    
    # 5. עדכון מיידי ראשוני
    invoke-static {v0}, Lcom/android/systemui/HebrewDateHelper;->updateHebrewDisplay(Landroid/widget/TextView;)V
    

    שלב 4: סיום.

    1. שמור הכל: צא מ-Dex Editor Plus ושמור שינויים.
    2. עדכון: MT Manager יבקש לעדכן את ה-APK. לחץ אישור ואל תסמן את "חתימה אוטומטית"!

     

    איני לוקח אחריות על שום נזק שיהיה כתוצאה ממדריך זה.

    בהצלחה!

    מדריכים -שיאומי f21 pro ו +f21 pro

  • הצעת ייעול | אתר לגרסאות שהועלו לפורום
    מחנה ידידיםמ מחנה ידידים

    אני באמצע ליצור אתר לגרסאות החינמיות שהועלו לפורום.
    אני רוצה אישור, עזרה בתפעול, פתיחה בנטפרי.


    @מזכירותי @שניאור-שמח @RearmostPant23 @מישהו12 @נוחעם-FM

    @י.-פל. לגבי נטפרי אם תוכל לעזור


    אשמח אם תתייגו את מי שיעזור בעניין

    עזרה הדדית - שיאומי f21 pro ו +f21 pro

  • שיתוף | יצור טלפון חדש בדוגמת הC2
    מחנה ידידיםמ מחנה ידידים

    למי שמעוניין- תמונות די מפורטות:

    29bb99db-11dc-467c-aec7-bcf29ff03a8d-WhatsApp Image 2026-01-18 at 21.20.56.png 16081cba-11d0-4e57-b435-bc6eb57a0be4-WhatsApp Image 2026-01-18 at 21.20.57 (1).png 9b5c3112-3a9c-4b5e-898f-09afc0b2d5a9-WhatsApp Image 2026-01-18 at 21.20.57.png 3924fba8-e978-4d26-a8fe-96e47ebc0805-WhatsApp Image 2026-01-18 at 21.20.58 (1).png f5fc09ee-0ac3-4544-a861-2d5ab9153cfd-WhatsApp Image 2026-01-18 at 21.20.58 (2).png e737d10f-e333-4690-b596-9b057309c532-WhatsApp Image 2026-01-18 at 21.20.58 (3).png 03b7c367-742f-467a-b127-47b92484a5e6-WhatsApp Image 2026-01-18 at 21.20.58.png 524c8375-d25b-4496-8309-ba6a2bcee098-WhatsApp Image 2026-01-18 at 21.20.59 (1).png 0fbc01ca-b9c2-413f-a070-050d619c0749-WhatsApp Image 2026-01-18 at 21.20.59 (2).png 72ebf2d4-1711-4f7e-8fe0-db504e7bb445-WhatsApp Image 2026-01-18 at 21.20.59.png 7e57e4a2-ef80-4372-aec8-a093122ffa90-WhatsApp Image 2026-01-18 at 21.21.00 (1).png bd5d9507-c858-4552-9274-200a82e9def2-WhatsApp Image 2026-01-18 at 21.21.00 (2).png d78d6f19-9e3c-44c2-85e5-9550ad5b8367-WhatsApp Image 2026-01-18 at 21.21.00.png f276352e-37ce-4e1a-ad16-b3017c411fe0-WhatsApp Image 2026-01-18 at 21.21.01 (1).png b09e5392-ee17-4d74-b2bd-c58b92ec6a84-WhatsApp Image 2026-01-18 at 21.21.01 (2).png 9edb0a51-a1cd-46b4-b8b6-b7dedf40ed4e-WhatsApp Image 2026-01-18 at 21.21.01 (3).png d34d633c-df17-422e-9f3d-6516525551e5-WhatsApp Image 2026-01-18 at 21.21.01.png 7b23588d-7f6f-4111-bfde-51f7aaa82237-WhatsApp Image 2026-01-18 at 21.21.02 (1).png 0938172c-f46a-4d88-af46-645415b59f99-WhatsApp Image 2026-01-18 at 21.21.02.png

    כללי - עזרה הדדית

  • שיתוף | אתר לגרסאות!
    מחנה ידידיםמ מחנה ידידים

    @שניאור-שמח ו @מישהו12 בבקשה
    1b2ede4f-38c0-4fe9-9e66-3ba76cfa427c-image.png

    עזרה הדדית - שיאומי f21 pro ו +f21 pro

  • שיתוף | מסך הבית של qin f21 pro עם תאריך עברי ומגירת אפליקציות!
    מחנה ידידיםמ מחנה ידידים

    גרסה משופרת!

    4b836ea3-66fc-4f45-97be-9510079efa01-image.jpeg

    מימין לשמאל - סגירת כל האפליקציות, צילום מסך האפליקציה שבמיקוד, שינוי רזולוציה, ושיתוף צילום המסך שדובר לעיל.

    תהנו!

    Launcher3QuickStep.apk

    @10110000 @נוחעם-FM

    עזרה הדדית - שיאומי f21 pro ו +f21 pro

  • בעיה | שימוש לרעה בפורום
    מחנה ידידיםמ מחנה ידידים

    יש מישהו ששולח אימיילים של פרסום לכל האימיילים שרשומים פה. יש מה לעשות עם זה?

    @שמואל @אלישי ?

    באגים/הצעות ייעול

  • המלצה | סקריפט לטמפרמונקי לסינון הנושאים לפי סוג! (מדריך, בעיה וכו')
    מחנה ידידיםמ מחנה ידידים

    תודה לperplexity 😄

    // ==UserScript==
    // @name         מתמחים טופ - סינון נושאים לפי תגיות (ריבוי תגיות + טעינה דינמית)
    // @namespace    http://tampermonkey.net/
    // @version      3.0
    // @description  סינון <li class="category-item"> בדף user/*/topics לפי תגיות span (המלצה, בקשה וכו'), כולל נושאים שנוספים בגלילה/דפדוף.‏
    // @match        https://mitmachim.top/user/*/topics
    // @match        https://www.mitmachim.top/user/*/topics
    // @grant        none
    // ==/UserScript==
    
    (function () {
      'use strict';
    
      // --- עזר בסיסי ---
    
      function getTagFromRow(row) {
        const link = row.querySelector('h3[component="topic/header"] a.text-reset');
        if (!link) return '';
        const span = link.querySelector('span');
        if (!span) return '';
        const clone = span.cloneNode(true);
        clone.querySelectorAll('i, svg').forEach(el => el.remove());
        return clone.textContent.replace(/\s+/g, ' ').trim();
      }
    
      function slugifyTag(tag) {
        return tag
          .replace(/\s+/g, '-')                 // רווחים -> מקף
          .replace(/[^\w\u0590-\u05FF-]/g, ''); // מסיר תווים בעייתיים (משאיר אותיות/ספרות/עברית/מקף)
      }
    
      // --- מצב גלובלי ---
    
      let currentRows = [];
      let currentTagInfos = [];
      let filterPanel = null;
    
      function getSelectedSlugs() {
        if (!filterPanel) return [];
        return Array.from(filterPanel.querySelectorAll('input[type="checkbox"]:checked'))
          .map(chk => chk.value);
      }
    
      // --- תיוג שורות לפי תגיות ---
    
      function addTagClasses(rows) {
        const tagSet = new Set();
    
        rows.forEach(row => {
          const tag = getTagFromRow(row);
          if (!tag) return;
    
          const slug = slugifyTag(tag);
          row.classList.add('topic-tag-' + slug);
          tagSet.add(JSON.stringify({ tag, slug }));
        });
    
        return Array.from(tagSet).map(str => JSON.parse(str));
      }
    
      // --- יצירת / עדכון פאנל סינון ---
    
      function ensureGlobalCSS() {
        if (document.getElementById('topics-tag-filter-css')) return;
    
        const css = `
          li.category-item[component="category/topic"] {
            display: flex;
          }
    
          body.has-topic-filter li.category-item[component="category/topic"] {
            display: none !important;
          }
    
          body.has-topic-filter li.category-item[component="category/topic"].topic-tag-selected {
            display: flex !important;
          }
        `;
        const style = document.createElement('style');
        style.id = 'topics-tag-filter-css';
        style.textContent = css;
        document.documentElement.appendChild(style);
      }
    
      function createOrUpdateFilterPanel(list, tagInfos) {
        ensureGlobalCSS();
    
        if (!filterPanel) {
          // יצירה ראשונית
          const panel = document.createElement('div');
          panel.style.margin = '10px 0';
          panel.style.padding = '10px';
          panel.style.border = '1px solid #ccc';
          panel.style.background = '#f9f9f9';
          panel.style.display = 'flex';
          panel.style.flexWrap = 'wrap';
          panel.style.alignItems = 'center';
          panel.style.gap = '8px';
          panel.style.direction = 'rtl';
    
          const title = document.createElement('span');
          title.textContent = 'סינון לפי תגיות נושא:';
          title.style.fontWeight = 'bold';
          panel.appendChild(title);
    
          const clearBtn = document.createElement('button');
          clearBtn.type = 'button';
          clearBtn.textContent = 'הכול';
          clearBtn.style.marginInlineStart = '8px';
          clearBtn.style.padding = '2px 6px';
          clearBtn.style.fontSize = '12px';
          clearBtn.addEventListener('click', () => {
            panel.querySelectorAll('input[type="checkbox"]').forEach(chk => chk.checked = false);
            applyFilter([]); // אין תגיות מסומנות
          });
          panel.appendChild(clearBtn);
    
          const tagsContainer = document.createElement('div');
          tagsContainer.className = 'tags-container';
          tagsContainer.style.display = 'flex';
          tagsContainer.style.flexWrap = 'wrap';
          tagsContainer.style.gap = '6px';
          tagsContainer.style.alignItems = 'center';
          panel.appendChild(tagsContainer);
    
          const note = document.createElement('span');
          note.textContent = ' (אפשר לבחור כמה תגיות; מוצגים נושאים שיש להם לפחות אחת מהן)';
          note.style.fontSize = '11px';
          note.style.color = '#666';
          note.style.width = '100%';
          panel.appendChild(note);
    
          list.parentElement.insertBefore(panel, list);
    
          panel.addEventListener('change', () => {
            const selected = getSelectedSlugs();
            applyFilter(selected);
          });
    
          filterPanel = panel;
        }
    
        // עדכון רשימת הצ'קבוקסים (איחוד תגיות מכל העמוד/גלילות)
        const tagsContainer = filterPanel.querySelector('.tags-container');
        const existingSlugs = new Set(Array.from(tagsContainer.querySelectorAll('input[type="checkbox"]')).map(chk => chk.value));
        const selectedBefore = new Set(getSelectedSlugs());
    
        tagInfos.forEach(info => {
          if (existingSlugs.has(info.slug)) return;
          const wrapper = document.createElement('label');
          wrapper.style.display = 'flex';
          wrapper.style.alignItems = 'center';
          wrapper.style.gap = '4px';
          wrapper.style.fontSize = '12px';
    
          const chk = document.createElement('input');
          chk.type = 'checkbox';
          chk.value = info.slug;
          if (selectedBefore.has(info.slug)) chk.checked = true;
    
          const span = document.createElement('span');
          span.textContent = info.tag;
    
          wrapper.appendChild(chk);
          wrapper.appendChild(span);
          tagsContainer.appendChild(wrapper);
        });
      }
    
      // --- סינון בפועל ---
    
      function applyFilter(selectedSlugs) {
        const rows = currentRows;
        if (!rows.length) return;
    
        if (!selectedSlugs || !selectedSlugs.length) {
          document.body.classList.remove('has-topic-filter');
          rows.forEach(row => {
            row.classList.remove('topic-tag-selected');
            row.style.display = 'flex';
          });
          return;
        }
    
        document.body.classList.add('has-topic-filter');
    
        rows.forEach(row => {
          const hasAny = selectedSlugs.some(slug => row.classList.contains('topic-tag-' + slug));
          if (hasAny) {
            row.classList.add('topic-tag-selected');
          } else {
            row.classList.remove('topic-tag-selected');
          }
        });
      }
    
      // --- סריקה מחדש של הדף (לדף חדש / גלילה חדשה) ---
    
      function rescan() {
        const root = document.querySelector('#ajaxify') || document.querySelector('#content') || document.body;
        if (!root) return;
    
        const rows = Array.from(root.querySelectorAll('li.category-item[component="category/topic"]'));
        if (!rows.length) return;
    
        currentRows = rows;
    
        const tagInfos = addTagClasses(rows);
        currentTagInfos = mergeTagInfos(currentTagInfos, tagInfos);
    
        const list = rows[0].parentElement;
        createOrUpdateFilterPanel(list, currentTagInfos);
    
        // להחיל מחדש את הסינון לפי מה שכבר מסומן
        const selected = getSelectedSlugs();
        if (selected.length) {
          applyFilter(selected);
        }
      }
    
      function mergeTagInfos(oldInfos, newInfos) {
        const map = new Map();
        [...oldInfos, ...newInfos].forEach(info => {
          map.set(info.slug, info);
        });
        return Array.from(map.values());
      }
    
      // --- התחלה + MutationObserver לטעינה דינמית ---
    
      function start() {
        rescan();
    
        const ajaxify = document.querySelector('#ajaxify') || document.querySelector('#content') || document.body;
        if (!ajaxify) return;
    
        const observer = new MutationObserver((mutations) => {
          // כל שינוי משמעותי ב־childList גורר rescan
          if (mutations.some(m => m.type === 'childList' && m.addedNodes.length)) {
            rescan();
          }
        });
    
        observer.observe(ajaxify, { childList: true, subtree: true });
      }
    
      if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', start);
      } else {
        start();
      }
    })();
    

    התקנה מהירה

    אופן השימוש בפורום

  • שיתוף | סקריפט שמתקן את ה3 נקודות בפופאפ של כרטיסי המשתמש
    מחנה ידידיםמ מחנה ידידים

    מתקן את זה
    72424180-e023-41d0-86b2-ccccce3bea5d-image.jpeg
    ומציג כך
    8da9e6e4-8b70-45aa-b1de-62cdb6a8db1e-image.jpeg

    הנה:

    // ==UserScript==
    // @name         NodeBB Cards - Fix Ellipsis
    // @namespace    http://tampermonkey.net/
    // @version      1.1
    // @match        https://mitmachim.top/*
    // @grant        none
    // @run-at       document-idle
    // ==/UserScript==
    
    (function () {
        'use strict';
    
        function fix() {
            document.querySelectorAll('.fa-ellipsis-v').forEach(el => {
                el.style.fontFamily = '"Font Awesome 7 Free"';
                el.style.fontWeight = '900';
            });
        }
    
        // מיד כשהדף נטען
        fix();
    
        // כל פעם שנוסף תוכן חדש (הפופאפ)
        new MutationObserver(fix).observe(document.documentElement, {
            childList: true,
            subtree: true
        });
    
        // ליתר ביטחון
        setInterval(fix, 500);
    })();
    

    התקנה מהירה

    אופן השימוש בפורום

  • בעיה | הצילו! קלוד עוקב אחרי!
    מחנה ידידיםמ מחנה ידידים

    אתמול עבדתי איתו על שיפורים לאתר קושחה.נט .
    והיום הוא אומר לי
    Screenshot_20260527-081037.png

    מה זה הדבר הזה?!

    עזרה הדדית - בינה מלאכותית
  • התחברות

  • אין לך חשבון עדיין? הרשמה

  • התחברו או הירשמו כדי לחפש.
  • פוסט ראשון
    פוסט אחרון
0
  • חוקי הפורום
  • פופולרי
  • לא נפתר
  • משתמשים
  • חיפוש גוגל בפורום
  • צור קשר