mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-12-25 14:32:20 +01:00
Timeline: restore the selected timeline at the next startup (#694)
* Timeline: restore the selected timeline at the next startup Signed-off-by: Yusuke Arakawa <nekolaboratory@users.noreply.github.com> * Rename: UserDefaultas label name Signed-off-by: Yusuke Arakawa <nekolaboratory@users.noreply.github.com> * Timeline: RawRepresentable of TimelineFilter Signed-off-by: Yusuke Arakawa <nekolaboratory@users.noreply.github.com> * Cleanup code * Supports RemoteTimelineFilter * Cleanup code * Safe saves last viewed status --------- Signed-off-by: Yusuke Arakawa <nekolaboratory@users.noreply.github.com> Co-authored-by: Yusuke Arakawa <nekolaboratory@users.noreply.github.com>
This commit is contained in:
parent
02060cb4cd
commit
dae7b85d3d
@ -20,6 +20,8 @@ struct TimelineTab: View {
|
|||||||
@State private var timeline: TimelineFilter
|
@State private var timeline: TimelineFilter
|
||||||
@State private var scrollToTopSignal: Int = 0
|
@State private var scrollToTopSignal: Int = 0
|
||||||
|
|
||||||
|
@AppStorage("last_timeline_filter") public var lastTimelineFilter: TimelineFilter = TimelineFilter.home
|
||||||
|
|
||||||
private let canFilterTimeline: Bool
|
private let canFilterTimeline: Bool
|
||||||
|
|
||||||
init(popToRootTab: Binding<Tab>, timeline: TimelineFilter? = nil) {
|
init(popToRootTab: Binding<Tab>, timeline: TimelineFilter? = nil) {
|
||||||
@ -43,7 +45,11 @@ struct TimelineTab: View {
|
|||||||
routerPath.client = client
|
routerPath.client = client
|
||||||
if !didAppear && canFilterTimeline {
|
if !didAppear && canFilterTimeline {
|
||||||
didAppear = true
|
didAppear = true
|
||||||
timeline = client.isAuth ? .home : .federated
|
if(client.isAuth) {
|
||||||
|
timeline = lastTimelineFilter
|
||||||
|
} else {
|
||||||
|
timeline = .federated
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Task {
|
Task {
|
||||||
await currentAccount.fetchLists()
|
await currentAccount.fetchLists()
|
||||||
@ -53,10 +59,18 @@ struct TimelineTab: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: client.isAuth, perform: { isAuth in
|
.onChange(of: client.isAuth, perform: { isAuth in
|
||||||
timeline = isAuth ? .home : .federated
|
if(client.isAuth) {
|
||||||
|
timeline = lastTimelineFilter
|
||||||
|
} else {
|
||||||
|
timeline = .federated
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.onChange(of: currentAccount.account?.id, perform: { _ in
|
.onChange(of: currentAccount.account?.id, perform: { _ in
|
||||||
timeline = client.isAuth && canFilterTimeline ? .home : .federated
|
if(client.isAuth && canFilterTimeline) {
|
||||||
|
timeline = lastTimelineFilter
|
||||||
|
} else {
|
||||||
|
timeline = .federated
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.onChange(of: $popToRootTab.wrappedValue) { popToRootTab in
|
.onChange(of: $popToRootTab.wrappedValue) { popToRootTab in
|
||||||
if popToRootTab == .timeline {
|
if popToRootTab == .timeline {
|
||||||
@ -70,6 +84,11 @@ struct TimelineTab: View {
|
|||||||
.onChange(of: currentAccount.account?.id) { _ in
|
.onChange(of: currentAccount.account?.id) { _ in
|
||||||
routerPath.path = []
|
routerPath.path = []
|
||||||
}
|
}
|
||||||
|
.onChange(of: timeline) { timeline in
|
||||||
|
if(timeline == .home || timeline == .federated || timeline == .local) {
|
||||||
|
lastTimelineFilter = timeline
|
||||||
|
}
|
||||||
|
}
|
||||||
.withSafariRouter()
|
.withSafariRouter()
|
||||||
.environmentObject(routerPath)
|
.environmentObject(routerPath)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public struct List: Decodable, Identifiable, Equatable, Hashable {
|
public struct List: Codable, Identifiable, Equatable, Hashable {
|
||||||
public let id: String
|
public let id: String
|
||||||
public let title: String
|
public let title: String
|
||||||
public let repliesPolicy: String
|
public let repliesPolicy: String
|
||||||
|
@ -136,3 +136,168 @@ public enum TimelineFilter: Hashable, Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension TimelineFilter: Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case home
|
||||||
|
case local
|
||||||
|
case federated
|
||||||
|
case trending
|
||||||
|
case hashtag
|
||||||
|
case list
|
||||||
|
case remoteLocal
|
||||||
|
case latest
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
let key = container.allKeys.first
|
||||||
|
switch key {
|
||||||
|
case .home:
|
||||||
|
self = .home
|
||||||
|
case .local:
|
||||||
|
self = .local
|
||||||
|
case .federated:
|
||||||
|
self = .federated
|
||||||
|
case .trending:
|
||||||
|
self = .trending
|
||||||
|
case .hashtag:
|
||||||
|
var nestedContainer = try container.nestedUnkeyedContainer(forKey: .hashtag)
|
||||||
|
let tag = try nestedContainer.decode(String.self)
|
||||||
|
let accountId = try nestedContainer.decode(String?.self)
|
||||||
|
self = .hashtag(
|
||||||
|
tag: tag,
|
||||||
|
accountId: accountId
|
||||||
|
)
|
||||||
|
case .list:
|
||||||
|
let list = try container.decode(
|
||||||
|
Models.List.self,
|
||||||
|
forKey: .list
|
||||||
|
)
|
||||||
|
self = .list(list: list)
|
||||||
|
case .remoteLocal:
|
||||||
|
var nestedContainer = try container.nestedUnkeyedContainer(forKey: .remoteLocal)
|
||||||
|
let server = try nestedContainer.decode(String.self)
|
||||||
|
let filter = try nestedContainer.decode(RemoteTimelineFilter.self)
|
||||||
|
self = .remoteLocal(
|
||||||
|
server: server,
|
||||||
|
filter: filter
|
||||||
|
)
|
||||||
|
case .latest:
|
||||||
|
self = .latest
|
||||||
|
default:
|
||||||
|
throw DecodingError.dataCorrupted(
|
||||||
|
DecodingError.Context(
|
||||||
|
codingPath: container.codingPath,
|
||||||
|
debugDescription: "Unabled to decode enum."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
switch self {
|
||||||
|
case .home:
|
||||||
|
try container.encode(CodingKeys.home.rawValue, forKey: .home)
|
||||||
|
case .local:
|
||||||
|
try container.encode(CodingKeys.local.rawValue, forKey: .local)
|
||||||
|
case .federated:
|
||||||
|
try container.encode(CodingKeys.federated.rawValue, forKey: .federated)
|
||||||
|
case .trending:
|
||||||
|
try container.encode(CodingKeys.trending.rawValue, forKey: .trending)
|
||||||
|
case .hashtag(let tag, let accountId):
|
||||||
|
var nestedContainer = container.nestedUnkeyedContainer(forKey: .hashtag)
|
||||||
|
try nestedContainer.encode(tag)
|
||||||
|
try nestedContainer.encode(accountId)
|
||||||
|
case .list(let list):
|
||||||
|
try container.encode(list, forKey: .list)
|
||||||
|
case .remoteLocal(let server, let filter):
|
||||||
|
var nestedContainer = container.nestedUnkeyedContainer(forKey: .hashtag)
|
||||||
|
try nestedContainer.encode(server)
|
||||||
|
try nestedContainer.encode(filter)
|
||||||
|
case .latest:
|
||||||
|
try container.encode(CodingKeys.latest.rawValue, forKey: .latest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TimelineFilter: RawRepresentable {
|
||||||
|
public init?(rawValue: String) {
|
||||||
|
guard let data = rawValue.data(using: .utf8),
|
||||||
|
let result = try? JSONDecoder().decode(TimelineFilter.self, from: data)
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
self = result
|
||||||
|
}
|
||||||
|
|
||||||
|
public var rawValue: String {
|
||||||
|
guard let data = try? JSONEncoder().encode(self),
|
||||||
|
let result = String(data: data, encoding: .utf8)
|
||||||
|
else {
|
||||||
|
return "[]"
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension RemoteTimelineFilter: Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case local
|
||||||
|
case federated
|
||||||
|
case trending
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
let key = container.allKeys.first
|
||||||
|
switch key {
|
||||||
|
case .local:
|
||||||
|
self = .local
|
||||||
|
case .federated:
|
||||||
|
self = .federated
|
||||||
|
case .trending:
|
||||||
|
self = .trending
|
||||||
|
default:
|
||||||
|
throw DecodingError.dataCorrupted(
|
||||||
|
DecodingError.Context(
|
||||||
|
codingPath: container.codingPath,
|
||||||
|
debugDescription: "Unabled to decode enum."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
switch self {
|
||||||
|
case .local:
|
||||||
|
try container.encode(CodingKeys.local.rawValue, forKey: .local)
|
||||||
|
case .federated:
|
||||||
|
try container.encode(CodingKeys.federated.rawValue, forKey: .federated)
|
||||||
|
case .trending:
|
||||||
|
try container.encode(CodingKeys.trending.rawValue, forKey: .trending)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension RemoteTimelineFilter: RawRepresentable {
|
||||||
|
public init?(rawValue: String) {
|
||||||
|
guard let data = rawValue.data(using: .utf8),
|
||||||
|
let result = try? JSONDecoder().decode(RemoteTimelineFilter.self, from: data)
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
self = result
|
||||||
|
}
|
||||||
|
|
||||||
|
public var rawValue: String {
|
||||||
|
guard let data = try? JSONEncoder().encode(self),
|
||||||
|
let result = String(data: data, encoding: .utf8)
|
||||||
|
else {
|
||||||
|
return "[]"
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user