Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  NotificationBannerHelper.swift   Sprache: JAVA

 

import Foundation
import GroupCalls
import NotificationBannerSwift
import ThreemaFramework
import ThreemaMacros

enum NotificationBannerHelper {
    static func newBanner(baseMessage: BaseMessageEntity) {
        DispatchQueue.main.async {
            // Reload CoreData object because of concurrency problem
            let businessInjector = BusinessInjector.ui
            let entityManager = businessInjector.entityManager
            
            guard let message = entityManager.entityFetcher
                .managedObject(with: baseMessage.objectID) as? PreviewableMessage else {
                return
            }

            let profileImageView = ProfilePictureImageView()
            var thumbnailImageView: UIImageView?
            
            var title = message.conversation.displayName
           
            if message.conversation.conversationCategory == .private {
                profileImageView.info = nil
            }
            else if message.conversation.isGroup {
                let group = businessInjector.groupManager.getGroup(conversation: baseMessage.conversation)
                profileImageView.info = .group(group)
            }
            else if let contact = message.conversation.contact {
                let businessContact = Contact(contactEntity: contact)
                profileImageView.info = .contact(businessContact)
            }
            else {
                profileImageView.info = .contact(nil)
            }
           
            if let imageMessageEntity = message as? ImageMessageEntity {
                if let thumbnail = imageMessageEntity.thumbnail {
                    thumbnailImageView = getThumbnail(for: thumbnail.uiImage())
                }
            }
            else if message is AudioMessageEntity {
                thumbnailImageView = getThumbnailAudio()
            }
            else if let fileMessageEntity = message as? FileMessageEntity {
                if fileMessageEntity.renderType == .voiceMessage {
                    thumbnailImageView = getThumbnailAudio()
                }
                else if let thumbnail = fileMessageEntity.thumbnail {
                    thumbnailImageView = getThumbnail(for: thumbnail.uiImage())
                    thumbnailImageView?.contentMode = .scaleAspectFit
                }
            }
            
            let titleFontDescriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .headline)
            let bodyFont = UIFont.preferredFont(forTextStyle: .subheadline)
            
            if message.conversation.conversationCategory == .private {
                title = #localize("private_message_label")
                thumbnailImageView = nil
                
                if message.isGroupMessage {
                    profileImageView.info = .group(nil)
                }
                else {
                    profileImageView.info = .contact(nil)
                }
            }
            
            let banner = FloatingNotificationBanner(
                title: title,
                subtitle: "",
                titleFont: UIFont.boldSystemFont(ofSize: titleFontDescriptor.pointSize),
                titleColor: .label,
                subtitleFont: bodyFont,
                subtitleColor: .label,
                leftView: profileImageView,
                rightView: thumbnailImageView,
                style: .info,
                colors: CustomBannerColors(),
                sideViewSize: 50.0
            )
            
            banner.transparency = 0.9
            banner.duration = 3.0
            banner.applyStyling(cornerRadius: 8)
            banner.subtitleLabel?.numberOfLines = 2
            banner.overrideUserInterfaceStyle = Colors.themeUserInterfaceStyle

            if let groupID = message.conversation.groupID {
                banner.identifier = groupID.hexEncodedString()
            }
            else {
                if let contact = message.conversation.contact {
                    banner.identifier = contact.identity
                }
            }
            
            banner.transparency = 0.9
            banner.duration = 3.0
            banner.applyStyling(cornerRadius: 8)
            banner.subtitleLabel?.numberOfLines = 2
            
            if message.conversation.conversationCategory != .private {
                banner.subtitleLabel?.attributedText = message.previewAttributedText(
                    for: .notificationBanner,
                    settingsStore: businessInjector.settingsStore
                )
            }
            
            banner.onTap = {
                banner.bannerQueue.dismissAllForced()
                // Switch to selected conversation
                NotificationCenter.default.post(
                    name: NSNotification.Name(rawValue: kNotificationShowConversation),
                    object: nil,
                    userInfo: [kKeyConversation: message.conversation]
                )
            }
            
            banner.onSwipeUp = {
                banner.bannerQueue.removeAll()
            }
            let shadowEdgeInsets = UIEdgeInsets(top: 8, left: 2, bottom: 0, right: 2)
            let topViewController = SceneDelegate.current?.keyWindowCurrentTopViewController
            let edgeInsets = bannerEdgeInsets(in: topViewController?.view)
            if Colors.theme == .dark {
                banner.show(
                    on: topViewController,
                    edgeInsets: edgeInsets,
                    shadowColor: Colors.shadowNotification,
                    shadowOpacity: 0.5,
                    shadowBlurRadius: 7,
                    shadowEdgeInsets: shadowEdgeInsets,
                )
            }
            else {
                banner.show(
                    on: topViewController,
                    edgeInsets: edgeInsets,
                    shadowColor: Colors.shadowNotification,
                    shadowOpacity: 1.0,
                    shadowBlurRadius: 10,
                    shadowEdgeInsets: shadowEdgeInsets
                )
            }
        }
    }

    /// Edge insets for `FloatingNotificationBanner.show(…)`, starting from the library's default of 8 on each side
    ///
    /// On iOS 27 `UIApplication.shared.statusBarOrientation` no longer reports portrait, so NotificationBanner's
    /// `shouldAdjustForDynamicIsland()` / `shouldAdjustForNotchFeaturedIphone()` are always false and it falls back to
    /// its 10 pt top spacer instead of 44 pt (Dynamic Island) or 40 pt (notch). This puts the banner under the status
    /// bar, so we add the skipped difference ourselves, using the same inset thresholds as the library's
    /// `hasDynamicIsland()` / `isNotchFeaturedIPhone()` and a regular vertical size class instead of portrait.
    /// - Parameter view: View the banner is added to (the parent view controller's view or the window)
    private static func bannerEdgeInsets(in view: UIView?) -> UIEdgeInsets {
        var edgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
        if #available(iOS 27.0, *), let view, view.traitCollection.verticalSizeClass == .regular {
            let libraryDefaultSpacerHeight: CGFloat = 10
            if view.safeAreaInsets.top > 50 {
                edgeInsets.top += 44 - libraryDefaultSpacerHeight
            }
            else if view.safeAreaInsets.bottom > 0 {
                edgeInsets.top += 40 - libraryDefaultSpacerHeight
            }
        }
        return edgeInsets
    }

    private static func getThumbnailAudio() -> UIImageView? {
        let image = UIImage(
            systemName: "mic.fill",
            withConfiguration: UIImage.SymbolConfiguration(textStyle: .body)
        )?
            .withRenderingMode(.alwaysTemplate)
        let thumbnailImageView = getThumbnail(for: image, contentMode: .center)
        // Tinting the image itself would bake in the color resolved for the ambient interface style. Tinting the image
        // view instead resolves it in the banner's interface style.
        thumbnailImageView?.tintColor = .label
        return thumbnailImageView
    }

    private static func getThumbnail(
        for image: UIImage?,
        contentMode: UIView.ContentMode = .scaleAspectFill
    ) -> UIImageView? {
        let thumbnailImageView = UIImageView(image: image)
        thumbnailImageView.contentMode = contentMode
        return thumbnailImageView
    }

    static func newBannerForStartGroupCall(
        conversationManagedObjectID: NSManagedObjectID,
        title: String,
        body: String,
        identifier: String
    ) {
        let titleFontDescriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .headline)
        let bodyFont = UIFont.preferredFont(forTextStyle: .subheadline)
        
        let businessInjector = BusinessInjector.ui
        let profilePictureView = ProfilePictureImageView()
        let markupParser = MarkupParser()
        
        if let conversation = businessInjector.entityManager.entityFetcher
            .existingObject(with: conversationManagedObjectID) as? ConversationEntity,
            conversation.conversationCategory != .private,
            let group = businessInjector.groupManager.getGroup(conversation: conversation) {
            profilePictureView.info = .group(group)
        }
        else {
            profilePictureView.info = .group(nil)
        }
        
        let banner = FloatingNotificationBanner(
            title: title,
            subtitle: body,
            titleFont: UIFont.boldSystemFont(ofSize: titleFontDescriptor.pointSize),
            titleColor: .label,
            subtitleFont: bodyFont,
            subtitleColor: .label,
            leftView: profilePictureView,
            rightView: nil,
            style: .info,
            colors: CustomBannerColors(),
            sideViewSize: 50.0
        )
        // See `newBanner(baseMessage:)`
        banner.overrideUserInterfaceStyle = Colors.themeUserInterfaceStyle

        banner.identifier = identifier
        banner.transparency = 0.9
        banner.duration = 3.0
        banner.applyStyling(cornerRadius: 8)
        banner.subtitleLabel?.numberOfLines = 2
        
        let bodyAttributedString = markupParser.previewString(
            for: body,
            font: bodyFont
        )
        banner.subtitleLabel!.attributedText = bodyAttributedString
        
        banner.onTap = {
            banner.bannerQueue.dismissAllForced()
            // switch to selected conversation
            let entityManager = businessInjector.entityManager
            entityManager.perform {
                if let conversation = entityManager.entityFetcher.managedObject(with: conversationManagedObjectID) {
                    NotificationCenter.default.post(
                        name: NSNotification.Name(rawValue: kNotificationShowConversation),
                        object: nil,
                        userInfo: [kKeyConversation: conversation]
                    )
                }
            }
        }
        
        banner.onSwipeUp = {
            banner.bannerQueue.removeAll()
        }
        let shadowEdgeInsets = UIEdgeInsets(top: 8, left: 2, bottom: 0, right: 2)
        // Without a parent view controller the banner is added to the window
        let edgeInsets = bannerEdgeInsets(in: SceneDelegate.current?.window)
        if Colors.theme == .dark {
            banner.show(
                edgeInsets: edgeInsets,
                shadowColor: Colors.shadowNotification,
                shadowOpacity: 0.5,
                shadowBlurRadius: 7,
                shadowEdgeInsets: shadowEdgeInsets
            )
        }
        else {
            banner.show(
                edgeInsets: edgeInsets,
                shadowColor: Colors.shadowNotification,
                shadowOpacity: 1.0,
                shadowBlurRadius: 10,
                shadowEdgeInsets: shadowEdgeInsets
            )
        }
    }
        
    static func dismissAllNotifications() {
        DispatchQueue.main.async {
            NotificationBannerQueue.default.dismissAllForced()
        }
    }
    
    /// Dismiss and remove all the banners for the contact (Threema Identity of contact) or the identity of the group
    /// (GroupID as hex)
    /// - Parameter identifier: Threema ID or GroupID as hex
    static func dismissAllNotifications(for identifier: String) {
        DispatchQueue.main.async {
            let banners = NotificationBannerQueue.default.banners
            for banner in banners {
                if banner.identifier == identifier {
                    if banner.isDisplaying == true {
                        banner.dismiss()
                    }
                    NotificationBannerQueue.default.removeBanner(banner)
                }
            }
        }
    }
}

final class CustomBannerColors: BannerColorsProtocol {
    func color(for style: BannerStyle) -> UIColor {
        switch style {
        case .danger: .systemRed
        case .info: Colors.backgroundNotification
        case .customView: Colors.backgroundNotification
        case .success: .systemGreen
        case .warning: .systemOrange
        }
    }
}

Messung
CHZG
849710093

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104842
#Domains=499168