diff --git a/CustomKeyboard/KeyboardAssets.xcassets/home_ai_icon.imageset/Contents.json b/CustomKeyboard/KeyboardAssets.xcassets/home_ai_icon.imageset/Contents.json new file mode 100644 index 0000000..5c5e11f --- /dev/null +++ b/CustomKeyboard/KeyboardAssets.xcassets/home_ai_icon.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "home_ai_icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "home_ai_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CustomKeyboard/KeyboardAssets.xcassets/home_ai_icon.imageset/home_ai_icon@2x.png b/CustomKeyboard/KeyboardAssets.xcassets/home_ai_icon.imageset/home_ai_icon@2x.png new file mode 100644 index 0000000..e334153 Binary files /dev/null and b/CustomKeyboard/KeyboardAssets.xcassets/home_ai_icon.imageset/home_ai_icon@2x.png differ diff --git a/CustomKeyboard/KeyboardAssets.xcassets/home_ai_icon.imageset/home_ai_icon@3x.png b/CustomKeyboard/KeyboardAssets.xcassets/home_ai_icon.imageset/home_ai_icon@3x.png new file mode 100644 index 0000000..1a4867e Binary files /dev/null and b/CustomKeyboard/KeyboardAssets.xcassets/home_ai_icon.imageset/home_ai_icon@3x.png differ diff --git a/CustomKeyboard/KeyboardAssets.xcassets/home_chat_icon.imageset/Contents.json b/CustomKeyboard/KeyboardAssets.xcassets/home_chat_icon.imageset/Contents.json new file mode 100644 index 0000000..f7f7caa --- /dev/null +++ b/CustomKeyboard/KeyboardAssets.xcassets/home_chat_icon.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "home_chat_icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "home_chat_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CustomKeyboard/KeyboardAssets.xcassets/home_chat_icon.imageset/home_chat_icon@2x.png b/CustomKeyboard/KeyboardAssets.xcassets/home_chat_icon.imageset/home_chat_icon@2x.png new file mode 100644 index 0000000..09dd0b9 Binary files /dev/null and b/CustomKeyboard/KeyboardAssets.xcassets/home_chat_icon.imageset/home_chat_icon@2x.png differ diff --git a/CustomKeyboard/KeyboardAssets.xcassets/home_chat_icon.imageset/home_chat_icon@3x.png b/CustomKeyboard/KeyboardAssets.xcassets/home_chat_icon.imageset/home_chat_icon@3x.png new file mode 100644 index 0000000..762cf2d Binary files /dev/null and b/CustomKeyboard/KeyboardAssets.xcassets/home_chat_icon.imageset/home_chat_icon@3x.png differ diff --git a/CustomKeyboard/KeyboardAssets.xcassets/home_emotion_icon.imageset/Contents.json b/CustomKeyboard/KeyboardAssets.xcassets/home_emotion_icon.imageset/Contents.json new file mode 100644 index 0000000..37c6f7c --- /dev/null +++ b/CustomKeyboard/KeyboardAssets.xcassets/home_emotion_icon.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "home_emotion_icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "home_emotion_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CustomKeyboard/KeyboardAssets.xcassets/home_emotion_icon.imageset/home_emotion_icon@2x.png b/CustomKeyboard/KeyboardAssets.xcassets/home_emotion_icon.imageset/home_emotion_icon@2x.png new file mode 100644 index 0000000..511516c Binary files /dev/null and b/CustomKeyboard/KeyboardAssets.xcassets/home_emotion_icon.imageset/home_emotion_icon@2x.png differ diff --git a/CustomKeyboard/KeyboardAssets.xcassets/home_emotion_icon.imageset/home_emotion_icon@3x.png b/CustomKeyboard/KeyboardAssets.xcassets/home_emotion_icon.imageset/home_emotion_icon@3x.png new file mode 100644 index 0000000..ed641e9 Binary files /dev/null and b/CustomKeyboard/KeyboardAssets.xcassets/home_emotion_icon.imageset/home_emotion_icon@3x.png differ diff --git a/CustomKeyboard/KeyboardAssets.xcassets/home_keyboard_icon.imageset/Contents.json b/CustomKeyboard/KeyboardAssets.xcassets/home_keyboard_icon.imageset/Contents.json new file mode 100644 index 0000000..a1613b4 --- /dev/null +++ b/CustomKeyboard/KeyboardAssets.xcassets/home_keyboard_icon.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "home_keyboard_icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "home_keyboard_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CustomKeyboard/KeyboardAssets.xcassets/home_keyboard_icon.imageset/home_keyboard_icon@2x.png b/CustomKeyboard/KeyboardAssets.xcassets/home_keyboard_icon.imageset/home_keyboard_icon@2x.png new file mode 100644 index 0000000..7b21e24 Binary files /dev/null and b/CustomKeyboard/KeyboardAssets.xcassets/home_keyboard_icon.imageset/home_keyboard_icon@2x.png differ diff --git a/CustomKeyboard/KeyboardAssets.xcassets/home_keyboard_icon.imageset/home_keyboard_icon@3x.png b/CustomKeyboard/KeyboardAssets.xcassets/home_keyboard_icon.imageset/home_keyboard_icon@3x.png new file mode 100644 index 0000000..91ae8fa Binary files /dev/null and b/CustomKeyboard/KeyboardAssets.xcassets/home_keyboard_icon.imageset/home_keyboard_icon@3x.png differ diff --git a/CustomKeyboard/KeyboardAssets.xcassets/keybord_bg_icon.imageset/Contents.json b/CustomKeyboard/KeyboardAssets.xcassets/keybord_bg_icon.imageset/Contents.json new file mode 100644 index 0000000..29eaf2f --- /dev/null +++ b/CustomKeyboard/KeyboardAssets.xcassets/keybord_bg_icon.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "keybord_bg_icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "keybord_bg_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CustomKeyboard/KeyboardAssets.xcassets/keybord_bg_icon.imageset/keybord_bg_icon@2x.png b/CustomKeyboard/KeyboardAssets.xcassets/keybord_bg_icon.imageset/keybord_bg_icon@2x.png new file mode 100644 index 0000000..379f585 Binary files /dev/null and b/CustomKeyboard/KeyboardAssets.xcassets/keybord_bg_icon.imageset/keybord_bg_icon@2x.png differ diff --git a/CustomKeyboard/KeyboardAssets.xcassets/keybord_bg_icon.imageset/keybord_bg_icon@3x.png b/CustomKeyboard/KeyboardAssets.xcassets/keybord_bg_icon.imageset/keybord_bg_icon@3x.png new file mode 100644 index 0000000..78af64d Binary files /dev/null and b/CustomKeyboard/KeyboardAssets.xcassets/keybord_bg_icon.imageset/keybord_bg_icon@3x.png differ diff --git a/CustomKeyboard/KeyboardViewController.m b/CustomKeyboard/KeyboardViewController.m index 5d9a9f8..0db22a5 100644 --- a/CustomKeyboard/KeyboardViewController.m +++ b/CustomKeyboard/KeyboardViewController.m @@ -299,6 +299,10 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center, } } +- (void)functionViewDidRequestSubscription:(KBFunctionView *)functionView { + [self showSubscriptionPanel]; +} + #pragma mark - KBKeyboardSubscriptionViewDelegate - (void)subscriptionViewDidTapClose:(KBKeyboardSubscriptionView *)view { diff --git a/CustomKeyboard/Network/WJXEventSource/WJXEventSource.m b/CustomKeyboard/Network/WJXEventSource/WJXEventSource.m index f588e77..4efff9a 100644 --- a/CustomKeyboard/Network/WJXEventSource/WJXEventSource.m +++ b/CustomKeyboard/Network/WJXEventSource/WJXEventSource.m @@ -181,12 +181,15 @@ didReceiveResponse:(NSURLResponse *)response } - (void)URLSession:(NSURLSession *)session - task:(NSURLSessionTask *)task + task:(NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error; { if (_closedByUser) { + _buffer = [NSMutableData data]; return; } + + [self _dispatchPlainBufferIfNeeded]; WJXEvent *event = [[WJXEvent alloc] initWithReadyState:WJXEventStateClosed]; if (nil == (event.error = error)) { @@ -239,13 +242,16 @@ didCompleteWithError:(nullable NSError *)error; WJXEvent *event = [[WJXEvent alloc] initWithReadyState:WJXEventStateOpen]; NSString *eventString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + if (eventString.length == 0) { return; } NSArray *lines = [eventString componentsSeparatedByCharactersInSet:NSCharacterSet.newlineCharacterSet]; + BOOL hasDataLine = NO; for (NSString *line in lines) { if ([line hasPrefix:@"id:"]) { event.eventId = [[line substringFromIndex:3] stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceCharacterSet]; } else if ([line hasPrefix:@"event:"]) { event.event = [[line substringFromIndex:6] stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceCharacterSet]; } else if ([line hasPrefix:@"data:"]) { + hasDataLine = YES; NSString *data = [[line substringFromIndex:5] stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceCharacterSet]; event.data = event.data ? [event.data stringByAppendingFormat:@"\n%@", data] : data; } else if ([line hasPrefix:@"retry:"]) { @@ -253,6 +259,13 @@ didCompleteWithError:(nullable NSError *)error; self.retryInterval = [retryString doubleValue] / 1000; } } + + if (!hasDataLine) { + NSString *trimmed = [eventString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if (trimmed.length > 0) { + event.data = trimmed; + } + } if (event.eventId) { self.lastEventId = event.eventId; @@ -272,6 +285,15 @@ didCompleteWithError:(nullable NSError *)error; }]; } +- (void)_dispatchPlainBufferIfNeeded +{ + if (_buffer.length == 0) { return; } + NSData *data = [_buffer copy]; + [_buffer setLength:0]; + if (data.length == 0) { return; } + [self _parseEventData:data]; +} + #pragma mark - #pragma mark Setters diff --git a/CustomKeyboard/View/KBFunctionView.h b/CustomKeyboard/View/KBFunctionView.h index 6266c07..f403171 100644 --- a/CustomKeyboard/View/KBFunctionView.h +++ b/CustomKeyboard/View/KBFunctionView.h @@ -12,6 +12,7 @@ @optional - (void)functionView:(KBFunctionView *_Nullable)functionView didTapToolActionAtIndex:(NSInteger)index; - (void)functionView:(KBFunctionView *_Nullable)functionView didRightTapToolActionAtIndex:(NSInteger)index; +- (void)functionViewDidRequestSubscription:(KBFunctionView *_Nullable)functionView; @end diff --git a/CustomKeyboard/View/KBFunctionView.m b/CustomKeyboard/View/KBFunctionView.m index a1cf788..5f6b0fc 100644 --- a/CustomKeyboard/View/KBFunctionView.m +++ b/CustomKeyboard/View/KBFunctionView.m @@ -24,6 +24,7 @@ #import "WJXEventSource.h" #import "KBTagItemModel.h" #import +#import "KBBizCode.h" @interface KBFunctionView () // UI @@ -347,6 +348,7 @@ NSError *error = nil; NSDictionary *payload = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error]; if (error || ![payload isKindOfClass:[NSDictionary class]]) { return; } + if ([self kb_handleBizErrorIfNeeded:payload]) { return; } NSString *type = payload[@"type"]; if (![type isKindOfClass:[NSString class]]) { return; } @@ -395,6 +397,32 @@ self.eventSourceDidReceiveDone = NO; } +- (BOOL)kb_handleBizErrorIfNeeded:(NSDictionary *)payload { + NSInteger code = KBBizCodeFromJSONObject(payload); + if (code == NSNotFound || code == KBBizCodeSuccess) { + return NO; + } + BOOL needSubscriptionGuide = (code == KBBizCodeQuotaExhausted); + NSString *msg = KBBizMessageFromJSONObject(payload); + if (msg.length == 0) { + msg = KBLocalized(@"拉取失败"); + } + NSError *bizError = [NSError errorWithDomain:@"KBStreamBizError" + code:code + userInfo:@{NSLocalizedDescriptionKey: msg}]; + [self kb_finishEventSourceWithError:bizError]; + if (needSubscriptionGuide) { + [self kb_requestSubscriptionGuide]; + } + return YES; +} + +- (void)kb_requestSubscriptionGuide { + if ([self.delegate respondsToSelector:@selector(functionViewDidRequestSubscription:)]) { + [self.delegate functionViewDidRequestSubscription:self]; + } +} + #pragma mark - Event Parsing - (NSString *)kb_normalizedLLMChunkString:(id)dataValue { diff --git a/CustomKeyboard/View/KBKeyboardSubscriptionView.m b/CustomKeyboard/View/KBKeyboardSubscriptionView.m index eeffc04..11b6476 100644 --- a/CustomKeyboard/View/KBKeyboardSubscriptionView.m +++ b/CustomKeyboard/View/KBKeyboardSubscriptionView.m @@ -17,7 +17,7 @@ static NSString * const kKBKeyboardSubscriptionCellId = @"kKBKeyboardSubscriptio @end @interface KBKeyboardSubscriptionView () -@property (nonatomic, strong) UIView *cardView; +@property (nonatomic, strong) UIImageView *cardView; @property (nonatomic, strong) UIButton *closeButton; @property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, strong) UIScrollView *featureScrollView; @@ -35,7 +35,6 @@ static NSString * const kKBKeyboardSubscriptionCellId = @"kKBKeyboardSubscriptio @property (nonatomic, assign, getter=isLoading) BOOL loading; @property (nonatomic, strong) CADisplayLink *featureDisplayLink; @property (nonatomic, assign) CGFloat featureLoopWidth; -@property (nonatomic, strong) CAGradientLayer *cardGradientLayer; @end @implementation KBKeyboardSubscriptionView @@ -56,7 +55,6 @@ static NSString * const kKBKeyboardSubscriptionCellId = @"kKBKeyboardSubscriptio - (void)layoutSubviews { [super layoutSubviews]; - self.cardGradientLayer.frame = self.cardView.bounds; self.featureLoopWidth = self.featureScrollView.contentSize.width * 0.5f; [self startFeatureTickerIfNeeded]; } @@ -98,10 +96,10 @@ static NSString * const kKBKeyboardSubscriptionCellId = @"kKBKeyboardSubscriptio - (void)setupCardView { [self addSubview:self.cardView]; [self.cardView mas_makeConstraints:^(MASConstraintMaker *make) { - make.left.equalTo(self.mas_left).offset(6); - make.right.equalTo(self.mas_right).offset(-6); - make.top.equalTo(self.mas_top).offset(4); - make.bottom.equalTo(self.mas_bottom).offset(-4); + make.left.equalTo(self.mas_left).offset(0); + make.right.equalTo(self.mas_right).offset(0); + make.top.equalTo(self.mas_top).offset(0); + make.bottom.equalTo(self.mas_bottom).offset(0); }]; [self.cardView addSubview:self.closeButton]; @@ -422,17 +420,13 @@ static NSString * const kKBKeyboardSubscriptionCellId = @"kKBKeyboardSubscriptio #pragma mark - Lazy -- (UIView *)cardView { +- (UIImageView *)cardView { if (!_cardView) { - _cardView = [[UIView alloc] init]; - _cardView.layer.cornerRadius = 20; - _cardView.layer.masksToBounds = YES; - _cardGradientLayer = [CAGradientLayer layer]; - _cardGradientLayer.colors = @[ (id)[UIColor colorWithRed:0.80 green:0.96 blue:0.91 alpha:1].CGColor, - (id)[UIColor colorWithRed:0.72 green:0.89 blue:0.98 alpha:1].CGColor ]; - _cardGradientLayer.startPoint = CGPointMake(0, 0); - _cardGradientLayer.endPoint = CGPointMake(1, 1); - [_cardView.layer insertSublayer:_cardGradientLayer atIndex:0]; + _cardView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"keybord_bg_icon"]]; +// _cardView.layer.cornerRadius = 20; +// _cardView.layer.masksToBounds = YES; + _cardView.contentMode = UIViewContentModeScaleAspectFill; + _cardView.clipsToBounds = true; } return _cardView; } diff --git a/Shared/KBBizCode.h b/Shared/KBBizCode.h index f5873aa..31b5853 100644 --- a/Shared/KBBizCode.h +++ b/Shared/KBBizCode.h @@ -76,6 +76,9 @@ typedef NS_ENUM(NSInteger, KBBizCode) { /// 特定收据无效 KBBizCodeReceiptError = 50016, + + /// 免费次数耗尽,需要订阅 + KBBizCodeQuotaExhausted = 50022, }; NS_ASSUME_NONNULL_BEGIN