mirror of
https://github.com/viq/NewsBlur.git
synced 2025-08-31 22:20:12 +00:00
#1720 (Grid view)
- Implemented theme colors. - Implemented the content length options. - Implemented the font size options. - Implemented the compact / comfortable options. - Improved the logic for the rounded corners on cards.
This commit is contained in:
parent
2b10b82c75
commit
aa88601905
5 changed files with 168 additions and 50 deletions
|
@ -17,10 +17,9 @@ struct CardView: View {
|
|||
var body: some View {
|
||||
ZStack(alignment: .leading) {
|
||||
if story.isSelected || cache.isGrid {
|
||||
RoundedRectangle(cornerRadius: 10).foregroundColor(.init(white: 0.9))
|
||||
RoundedRectangle(cornerRadius: 10).foregroundColor(highlightColor)
|
||||
|
||||
CardFeedBarView(cache: cache, story: story)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
.padding(.leading, 2)
|
||||
} else {
|
||||
CardFeedBarView(cache: cache, story: story)
|
||||
|
@ -39,15 +38,16 @@ struct CardView: View {
|
|||
}
|
||||
|
||||
HStack {
|
||||
if !cache.isGrid, cache.settings.listPreview.isLeft, let previewImage {
|
||||
if !cache.isGrid, cache.settings.preview.isLeft, let previewImage {
|
||||
listPreview(image: previewImage)
|
||||
}
|
||||
|
||||
CardContentView(cache: cache, story: story)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
|
||||
.padding(15)
|
||||
.padding([.leading, .trailing], 15)
|
||||
.padding([.top, .bottom], cache.settings.spacing == .compact ? 10 : 15)
|
||||
|
||||
if !cache.isGrid, !cache.settings.listPreview.isLeft, let previewImage {
|
||||
if !cache.isGrid, !cache.settings.preview.isLeft, let previewImage {
|
||||
listPreview(image: previewImage)
|
||||
|
||||
// Image(uiImage: previewImage)
|
||||
|
@ -60,6 +60,9 @@ struct CardView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.if(cache.isGrid || story.isSelected) { view in
|
||||
view.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
}
|
||||
.if(story.isSelected) { view in
|
||||
view.padding(10)
|
||||
}
|
||||
|
@ -130,8 +133,16 @@ struct CardView: View {
|
|||
// }
|
||||
// }
|
||||
|
||||
var highlightColor: Color {
|
||||
if cache.isGrid {
|
||||
return Color.themed([0xFDFCFA, 0xFFFDEF, 0x4F4F4F, 0x292B2C])
|
||||
} else {
|
||||
return Color.themed([0xFFFDEF, 0xEEECCD, 0x303A40, 0x303030])
|
||||
}
|
||||
}
|
||||
|
||||
var previewImage: UIImage? {
|
||||
guard cache.settings.listPreview != .none, let image = cache.appDelegate.cachedImage(forStoryHash: story.hash), image.isKind(of: UIImage.self) else {
|
||||
guard cache.settings.preview != .none, let image = cache.appDelegate.cachedImage(forStoryHash: story.hash), image.isKind(of: UIImage.self) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -151,9 +162,9 @@ struct CardView: View {
|
|||
|
||||
@ViewBuilder
|
||||
func listPreview(image: UIImage) -> some View {
|
||||
let isLeft = cache.settings.listPreview.isLeft
|
||||
let isLeft = cache.settings.preview.isLeft
|
||||
|
||||
if cache.settings.listPreview.isSmall {
|
||||
if cache.settings.preview.isSmall {
|
||||
Image(uiImage: image)
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
|
@ -167,7 +178,7 @@ struct CardView: View {
|
|||
.resizable()
|
||||
.scaledToFill()
|
||||
.frame(width: 90)
|
||||
.cornerRadius(10, corners: isLeft || !story.isSelected ? [] : [.topRight, .bottomRight])
|
||||
.clipped()
|
||||
.padding(.leading, isLeft ? 8 : -10)
|
||||
.padding(.trailing, isLeft ? -10 : 0)
|
||||
}
|
||||
|
@ -208,8 +219,9 @@ struct CardContentView: View {
|
|||
.padding(.leading, 24)
|
||||
|
||||
Text(story.feedName)
|
||||
.font(.custom("WhitneySSm-Medium", size: 10, relativeTo: .caption))
|
||||
.font(font(named: "WhitneySSm-Medium", size: 10))
|
||||
.lineLimit(1)
|
||||
.foregroundColor(feedColor)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,14 +250,28 @@ struct CardContentView: View {
|
|||
}
|
||||
|
||||
Text(story.title)
|
||||
.font(.custom("WhitneySSm-Medium", size: 18, relativeTo: .caption).bold())
|
||||
.font(font(named: "WhitneySSm-Medium", size: 18).bold())
|
||||
.foregroundColor(titleColor)
|
||||
.lineLimit(cache.isGrid ? StorySettings.Content.titleLimit : cache.settings.content.limit)
|
||||
.truncationMode(.tail)
|
||||
}
|
||||
Text(story.content.prefix(400))
|
||||
.font(.custom("WhitneySSm-Book", size: 13, relativeTo: .caption))
|
||||
.padding(.top, 5)
|
||||
.padding(.bottom, cache.settings.spacing == .compact ? -5 : 0)
|
||||
|
||||
if cache.isGrid || cache.settings.content != .title {
|
||||
Text(story.content)
|
||||
.font(font(named: "WhitneySSm-Book", size: 13))
|
||||
.foregroundColor(contentColor)
|
||||
.lineLimit(cache.isGrid ? StorySettings.Content.contentLimit : cache.settings.content.limit)
|
||||
.truncationMode(.tail)
|
||||
.padding(.top, 5)
|
||||
.padding(.bottom, cache.settings.spacing == .compact ? -5 : 0)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(story.dateAndAuthor)
|
||||
.font(.custom("WhitneySSm-Medium", size: 10, relativeTo: .caption))
|
||||
.font(font(named: "WhitneySSm-Medium", size: 10))
|
||||
.foregroundColor(dateAndAuthorColor)
|
||||
.padding(.top, 5)
|
||||
}
|
||||
}
|
||||
|
@ -270,6 +296,40 @@ struct CardContentView: View {
|
|||
return UIImage(named: "indicator-unread")
|
||||
}
|
||||
}
|
||||
|
||||
func font(named: String, size: CGFloat) -> Font {
|
||||
return Font.custom(named, size: size + cache.settings.fontSize.offset, relativeTo: .caption)
|
||||
}
|
||||
|
||||
var feedColor: Color {
|
||||
return contentColor
|
||||
}
|
||||
|
||||
var titleColor: Color {
|
||||
if story.isSelected {
|
||||
return Color.themed([0x686868, 0xA0A0A0])
|
||||
} else if story.isRead {
|
||||
return Color.themed([0x585858, 0x585858, 0x989898, 0x888888])
|
||||
} else {
|
||||
return Color.themed([0x111111, 0x333333, 0xD0D0D0, 0xCCCCCC])
|
||||
}
|
||||
}
|
||||
|
||||
var contentColor: Color {
|
||||
if story.isSelected, story.isRead {
|
||||
return Color.themed([0xB8B8B8, 0xB8B8B8, 0xA0A0A0, 0x707070])
|
||||
} else if story.isSelected {
|
||||
return Color.themed([0x888785, 0x686868, 0xA9A9A9, 0x989898])
|
||||
} else if story.isRead {
|
||||
return Color.themed([0xB8B8B8, 0xB8B8B8, 0xA0A0A0, 0x707070])
|
||||
} else {
|
||||
return Color.themed([0x404040, 0x404040, 0xC0C0C0, 0xB0B0B0])
|
||||
}
|
||||
}
|
||||
|
||||
var dateAndAuthorColor: Color {
|
||||
return contentColor
|
||||
}
|
||||
}
|
||||
|
||||
struct CardFeedBarView: View {
|
||||
|
|
|
@ -71,6 +71,7 @@ struct FeedDetailGridView: View {
|
|||
view.padding()
|
||||
}
|
||||
}
|
||||
.background(Color.themed([0xF4F4F4, 0xFFFDEF, 0x4F4F4F, 0x101010]))
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
|
|
|
@ -19,7 +19,7 @@ struct StoryView: View {
|
|||
var body: some View {
|
||||
VStack {
|
||||
ZStack {
|
||||
Color(white: 0.9)
|
||||
Color.themed([0xFFFDEF, 0xEEECCD, 0x303A40, 0x303030])
|
||||
|
||||
HStack {
|
||||
Text(story.title)
|
||||
|
@ -36,7 +36,7 @@ struct StoryView: View {
|
|||
}
|
||||
}
|
||||
.font(.custom("WhitneySSm-Medium", size: 14, relativeTo: .body))
|
||||
.foregroundColor(.secondary)
|
||||
.foregroundColor(Color.themed([0x686868, 0xA0A0A0]))
|
||||
.frame(height: 50)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
.onTapGesture {
|
||||
|
@ -48,7 +48,7 @@ struct StoryView: View {
|
|||
}
|
||||
|
||||
var previewImage: UIImage? {
|
||||
guard cache.settings.listPreview != .none, let image = cache.appDelegate.cachedImage(forStoryHash: story.hash), image.isKind(of: UIImage.self) else {
|
||||
guard cache.settings.preview != .none, let image = cache.appDelegate.cachedImage(forStoryHash: story.hash), image.isKind(of: UIImage.self) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ class Story: Identifiable {
|
|||
var content = ""
|
||||
var dateString = ""
|
||||
var timestamp = 0
|
||||
var isRead = false
|
||||
var isSaved = false
|
||||
var isShared = false
|
||||
var score = 0
|
||||
|
@ -99,6 +100,7 @@ class Story: Identifiable {
|
|||
score = Int(NewsBlurAppDelegate.computeStoryScore(intelligence))
|
||||
}
|
||||
|
||||
isRead = score < 0
|
||||
isRiverOrSocial = storiesCollection.isRiverOrSocial
|
||||
}
|
||||
|
||||
|
@ -107,9 +109,9 @@ class Story: Identifiable {
|
|||
let scanner = Scanner(string: hex)
|
||||
var color: Int64 = 0
|
||||
scanner.scanHexInt64(&color)
|
||||
let array = [NSNumber(value: color)]
|
||||
let value = Int(color)
|
||||
|
||||
return ThemeManager.color(fromRGB: array)
|
||||
return ThemeManager.shared.fixedColor(fromRGB: value) ?? UIColor.gray
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,19 +151,44 @@ class StoryCache: ObservableObject {
|
|||
class StorySettings {
|
||||
let defaults = UserDefaults.standard
|
||||
|
||||
//TODO: 🚧
|
||||
// var listContent: Int {
|
||||
// NSString *preferenceKey = @"story_list_preview_text_size";
|
||||
// NSArray *titles = @[@"Title", @"content_preview_small.png", @"content_preview_medium.png", @"content_preview_large.png"];
|
||||
// NSArray *values = @[@"title", @"short", @"medium", @"long"];
|
||||
// }
|
||||
enum Content: String, RawRepresentable {
|
||||
case title
|
||||
case short
|
||||
case medium
|
||||
case long
|
||||
|
||||
static let titleLimit = 6
|
||||
|
||||
static let contentLimit = 10
|
||||
|
||||
var limit: Int {
|
||||
switch self {
|
||||
case .title:
|
||||
return 6
|
||||
case .short:
|
||||
return 2
|
||||
case .medium:
|
||||
return 4
|
||||
case .long:
|
||||
return 6
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ListPreview {
|
||||
var content: Content {
|
||||
if let string = defaults.string(forKey: "story_list_preview_text_size"), let value = Content(rawValue: string) {
|
||||
return value
|
||||
} else {
|
||||
return .short
|
||||
}
|
||||
}
|
||||
|
||||
enum Preview: String, RawRepresentable {
|
||||
case none
|
||||
case smallLeft
|
||||
case largeLeft
|
||||
case largeRight
|
||||
case smallRight
|
||||
case smallLeft = "small_left"
|
||||
case largeLeft = "large_left"
|
||||
case largeRight = "large_right"
|
||||
case smallRight = "small_right"
|
||||
|
||||
var isLeft: Bool {
|
||||
return [.smallLeft, .largeLeft].contains(self)
|
||||
|
@ -172,31 +199,57 @@ class StorySettings {
|
|||
}
|
||||
}
|
||||
|
||||
var listPreview: ListPreview {
|
||||
switch defaults.string(forKey: "story_list_preview_images_size") {
|
||||
case "none":
|
||||
return .none
|
||||
case "small_left":
|
||||
return .smallLeft
|
||||
case "large_left":
|
||||
return .largeLeft
|
||||
case "large_right":
|
||||
return .largeRight
|
||||
default:
|
||||
var preview: Preview {
|
||||
if let string = defaults.string(forKey: "story_list_preview_images_size"), let value = Preview(rawValue: string) {
|
||||
return value
|
||||
} else {
|
||||
return .smallRight
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: 🚧
|
||||
// NSString *preferenceKey = @"feed_list_font_size";
|
||||
// NSArray *titles = @[@"XS", @"S", @"M", @"L", @"XL"];
|
||||
// NSArray *values = @[@"xs", @"small", @"medium", @"large", @"xl"];
|
||||
enum FontSize: String, RawRepresentable {
|
||||
case xs
|
||||
case small
|
||||
case medium
|
||||
case large
|
||||
case xl
|
||||
|
||||
var offset: CGFloat {
|
||||
switch self {
|
||||
case .xs:
|
||||
return -2
|
||||
case .small:
|
||||
return -1
|
||||
case .medium:
|
||||
return 0
|
||||
case .large:
|
||||
return 1
|
||||
case .xl:
|
||||
return 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: 🚧
|
||||
// preferenceKey = @"feed_list_spacing";
|
||||
// titles = @[@"Compact", @"Comfortable"];
|
||||
// values = @[@"compact", @"comfortable"];
|
||||
var fontSize: FontSize {
|
||||
if let string = defaults.string(forKey: "feed_list_font_size"), let value = FontSize(rawValue: string) {
|
||||
return value
|
||||
} else {
|
||||
return .medium
|
||||
}
|
||||
}
|
||||
|
||||
enum Spacing: String, RawRepresentable {
|
||||
case compact
|
||||
case comfortable
|
||||
}
|
||||
|
||||
var spacing: Spacing {
|
||||
if let string = defaults.string(forKey: "feed_list_spacing"), let value = Spacing(rawValue: string) {
|
||||
return value
|
||||
} else {
|
||||
return .comfortable
|
||||
}
|
||||
}
|
||||
|
||||
// enum GridColumns: String {
|
||||
// case auto = "auto"
|
||||
|
|
|
@ -53,4 +53,8 @@ extension Color {
|
|||
return Color(red: .random(in: 0...1), green: .random(in: 0...1), blue: .random(in: 0...1)
|
||||
)
|
||||
}
|
||||
|
||||
static func themed(_ hex: [NSNumber]) -> Color {
|
||||
return Color(ThemeManager.color(fromRGB: hex))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue