diff --git a/app-ios/Sources/TimetableDetailFeature/InformationRow.swift b/app-ios/Sources/TimetableDetailFeature/InformationRow.swift
new file mode 100644
index 000000000..907d52b9f
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/InformationRow.swift
@@ -0,0 +1,48 @@
+import SwiftUI
+
+struct InformationRow: View {
+ private let icon: Image
+ private let title: String
+ private let content: String
+
+ init(
+ icon: Image,
+ title: String,
+ content: String
+ ) {
+ self.icon = icon
+ self.title = title
+ self.content = content
+ }
+
+ var body: some View {
+ HStack {
+ icon
+ HStack(spacing: 12) {
+ Text(title)
+ .font(.callout)
+ .foregroundStyle(Color(.surfaceVariant))
+ .bold()
+ HStack {
+ Text(content)
+ .font(.callout)
+ .foregroundStyle(Color(.onSurface))
+ }
+
+ }
+ }
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .foregroundStyle(
+ Color.white
+ )
+ }
+}
+
+#Preview {
+ InformationRow(
+ icon: Image(systemName: "clock"),
+ title: String(localized: "TimeTableDetailDate", bundle: .module),
+ content: SampleData.dateValue
+ )
+}
+
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Localizable.xcstrings b/app-ios/Sources/TimetableDetailFeature/Resource/Localizable.xcstrings
new file mode 100644
index 000000000..99102813d
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Localizable.xcstrings
@@ -0,0 +1,175 @@
+{
+ "sourceLanguage" : "en",
+ "strings" : {
+ "DroidKaigiアプリで見るアーキテクチャの変遷" : {
+
+ },
+ "name" : {
+
+ },
+ "TimeTableDetailApplicants" : {
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Applicants"
+ }
+ },
+ "ja" : {
+ "stringUnit" : {
+ "state" : "needs_review",
+ "value" : "対象者"
+ }
+ }
+ }
+ },
+ "TimeTableDetailArchive" : {
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Archive"
+ }
+ },
+ "ja" : {
+ "stringUnit" : {
+ "state" : "needs_review",
+ "value" : "アーカイブ"
+ }
+ }
+ }
+ },
+ "TimeTableDetailCategory" : {
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Category"
+ }
+ },
+ "ja" : {
+ "stringUnit" : {
+ "state" : "needs_review",
+ "value" : "カテゴリ"
+ }
+ }
+ }
+ },
+ "TimeTableDetailDate" : {
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Date"
+ }
+ },
+ "ja" : {
+ "stringUnit" : {
+ "state" : "needs_review",
+ "value" : "日付"
+ }
+ }
+ }
+ },
+ "TimeTableDetailLanguage" : {
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Language"
+ }
+ },
+ "ja" : {
+ "stringUnit" : {
+ "state" : "needs_review",
+ "value" : "対応言語"
+ }
+ }
+ }
+ },
+ "TimeTableDetailLocation" : {
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Location"
+ }
+ },
+ "ja" : {
+ "stringUnit" : {
+ "state" : "needs_review",
+ "value" : "場所"
+ }
+ }
+ }
+ },
+ "TimeTableDetailReadMore" : {
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Read more"
+ }
+ },
+ "ja" : {
+ "stringUnit" : {
+ "state" : "needs_review",
+ "value" : "続きを読む"
+ }
+ }
+ }
+ },
+ "TimeTableDetailSlide" : {
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Slide"
+ }
+ },
+ "ja" : {
+ "stringUnit" : {
+ "state" : "needs_review",
+ "value" : "スライド"
+ }
+ }
+ }
+ },
+ "TimeTableDetailSpeaker" : {
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Speaker"
+ }
+ },
+ "ja" : {
+ "stringUnit" : {
+ "state" : "needs_review",
+ "value" : "スピーカー"
+ }
+ }
+ }
+ },
+ "TimeTableDetailVideo" : {
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Video"
+ }
+ },
+ "ja" : {
+ "stringUnit" : {
+ "state" : "needs_review",
+ "value" : "動画"
+ }
+ }
+ }
+ },
+ "手を動かして実践してひとへのヒントとなります\nCoroutinesを使いたいと感じているひと\nよりモダンで効率的なAndroidアプリ開発に興味があるひと\n新しいパラダイムをいち早く知りたいひと\nアプリ開発が複雑だと感じるひと\nアプリ開発経験を前提としてあったほうが楽しめます" : {
+
+ }
+ },
+ "version" : "1.0"
+}
\ No newline at end of file
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Avatar.imageset/Avatar.png b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Avatar.imageset/Avatar.png
new file mode 100644
index 000000000..3265a59c5
Binary files /dev/null and b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Avatar.imageset/Avatar.png differ
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Avatar.imageset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Avatar.imageset/Contents.json
new file mode 100644
index 000000000..08ba02927
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Avatar.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "Avatar.png",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Background.colorset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Background.colorset/Contents.json
new file mode 100644
index 000000000..2f20e84d1
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Background.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0x24",
+ "green" : "0x20",
+ "red" : "0x04"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Button.colorset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Button.colorset/Contents.json
new file mode 100644
index 000000000..ac6590d14
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Button.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0xDA",
+ "green" : "0xD6",
+ "red" : "0xBB"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Contents.json
new file mode 100644
index 000000000..73c00596a
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/On Primary.colorset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/On Primary.colorset/Contents.json
new file mode 100644
index 000000000..9dbdacca8
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/On Primary.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0x28",
+ "green" : "0x38",
+ "red" : "0x00"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/On Surface.colorset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/On Surface.colorset/Contents.json
new file mode 100644
index 000000000..6ce422fa1
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/On Surface.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0xC4",
+ "green" : "0xC7",
+ "red" : "0xC5"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Outline Variant.colorset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Outline Variant.colorset/Contents.json
new file mode 100644
index 000000000..d1f7fa7ac
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Outline Variant.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0x44",
+ "green" : "0x49",
+ "red" : "0x40"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Outline.colorset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Outline.colorset/Contents.json
new file mode 100644
index 000000000..a4ab530a5
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Outline.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0x8D",
+ "green" : "0x93",
+ "red" : "0x89"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Primary.colorset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Primary.colorset/Contents.json
new file mode 100644
index 000000000..7aca1c73f
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Primary.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0xB0",
+ "green" : "0xDC",
+ "red" : "0x61"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Secondary Container.colorset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Secondary Container.colorset/Contents.json
new file mode 100644
index 000000000..d88179f42
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Secondary Container.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0x41",
+ "green" : "0x4B",
+ "red" : "0x35"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Surface Container.colorset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Surface Container.colorset/Contents.json
new file mode 100644
index 000000000..548722215
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Surface Container.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0x1E",
+ "green" : "0x20",
+ "red" : "0x1D"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Surface Variant.colorset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Surface Variant.colorset/Contents.json
new file mode 100644
index 000000000..901e7965b
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/Surface Variant.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "194",
+ "green" : "201",
+ "red" : "191"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_add_calendar.imageset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_add_calendar.imageset/Contents.json
new file mode 100644
index 000000000..cd73e8810
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_add_calendar.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "ic_add_calendar.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_add_calendar.imageset/ic_add_calendar.svg b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_add_calendar.imageset/ic_add_calendar.svg
new file mode 100644
index 000000000..b4d74e088
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_add_calendar.imageset/ic_add_calendar.svg
@@ -0,0 +1,8 @@
+
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_category.imageset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_category.imageset/Contents.json
new file mode 100644
index 000000000..119b2b3d2
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_category.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "ic_category.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_category.imageset/ic_category.svg b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_category.imageset/ic_category.svg
new file mode 100644
index 000000000..dbc01ee53
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_category.imageset/ic_category.svg
@@ -0,0 +1,8 @@
+
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_document.imageset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_document.imageset/Contents.json
new file mode 100644
index 000000000..77d87ad9c
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_document.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "ic_document.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_document.imageset/ic_document.svg b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_document.imageset/ic_document.svg
new file mode 100644
index 000000000..f2779e967
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_document.imageset/ic_document.svg
@@ -0,0 +1,8 @@
+
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_favorite.imageset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_favorite.imageset/Contents.json
new file mode 100644
index 000000000..6eb84ed4e
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_favorite.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "ic_favorite.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_favorite.imageset/ic_favorite.svg b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_favorite.imageset/ic_favorite.svg
new file mode 100644
index 000000000..8542f5563
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_favorite.imageset/ic_favorite.svg
@@ -0,0 +1,3 @@
+
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_language.imageset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_language.imageset/Contents.json
new file mode 100644
index 000000000..cf770ff19
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_language.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "ic_language.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_language.imageset/ic_language.svg b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_language.imageset/ic_language.svg
new file mode 100644
index 000000000..ee07d5014
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_language.imageset/ic_language.svg
@@ -0,0 +1,8 @@
+
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_location_on.imageset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_location_on.imageset/Contents.json
new file mode 100644
index 000000000..0cc07bd09
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_location_on.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "ic_location_on.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_location_on.imageset/ic_location_on.svg b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_location_on.imageset/ic_location_on.svg
new file mode 100644
index 000000000..b654e7574
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_location_on.imageset/ic_location_on.svg
@@ -0,0 +1,8 @@
+
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_play.imageset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_play.imageset/Contents.json
new file mode 100644
index 000000000..059067738
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_play.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "ic_play.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_play.imageset/ic_play.svg b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_play.imageset/ic_play.svg
new file mode 100644
index 000000000..f46ff6b66
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_play.imageset/ic_play.svg
@@ -0,0 +1,8 @@
+
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_schedule.imageset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_schedule.imageset/Contents.json
new file mode 100644
index 000000000..802ffe376
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_schedule.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "ic_schedule.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_schedule.imageset/ic_schedule.svg b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_schedule.imageset/ic_schedule.svg
new file mode 100644
index 000000000..5dbe7b0e2
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_schedule.imageset/ic_schedule.svg
@@ -0,0 +1,8 @@
+
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_share.imageset/Contents.json b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_share.imageset/Contents.json
new file mode 100644
index 000000000..070352f9a
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_share.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "ic_share.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true
+ }
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_share.imageset/ic_share.svg b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_share.imageset/ic_share.svg
new file mode 100644
index 000000000..ad9abca46
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/Resource/Media.xcassets/ic_share.imageset/ic_share.svg
@@ -0,0 +1,3 @@
+
diff --git a/app-ios/Sources/TimetableDetailFeature/SampleData.swift b/app-ios/Sources/TimetableDetailFeature/SampleData.swift
new file mode 100644
index 000000000..c37c4b99b
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/SampleData.swift
@@ -0,0 +1,10 @@
+enum SampleData {
+ static let title = "DroidKaigiアプリで見るアーキテクチャの変遷"
+ static let dateValue = "2023.09.14 / 11:20 ~ 12:00 (40分)"
+ static let locationValue = "Arctic Fox (1F)"
+ static let languageValue = "日本語(英語通訳あり)"
+ static let categoryValue = "Jetpack Compose"
+ static let sessionDescription = "Kotlin Coroutinesは非同期処理をシンプルに記述できるKotlinの言語機能です。実験的な機能としてこれまでも提供されてきましたがKotlin 1.3で正式にリリース予定です。Androidの誕生から10年たちアプリの利用シーンが増えたKotlin Coroutinesは非同期処理をシンプルに記述できるKotlinの言語機能です。実験的な機能としてこれまでも提供されてきましたがKotlin 1.3で正式にリリース予定です。Androidの誕生から10年たちアプリの利用シーンが増えた."
+ static let applicants = "手を動かして実践してひとへのヒントとなります\nCoroutinesを使いたいと感じているひと\nよりモダンで効率的なAndroidアプリ開発に興味があるひと\n新しいパラダイムをいち早く知りたいひと\nアプリ開発が複雑だと感じるひと\nアプリ開発経験を前提としてあったほうが楽しめます"
+ static let name = "name"
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/SessionDescriptionView.swift b/app-ios/Sources/TimetableDetailFeature/SessionDescriptionView.swift
new file mode 100644
index 000000000..8e8ceaff3
--- /dev/null
+++ b/app-ios/Sources/TimetableDetailFeature/SessionDescriptionView.swift
@@ -0,0 +1,54 @@
+import SwiftUI
+
+struct SessionDescriptionView: View {
+ @State private var isDescriptionExpanded: Bool = false
+ @State private var canBeExpanded: Bool = false
+ let content: String
+
+ init(content: String) {
+ self.content = content
+ }
+
+ var body: some View {
+ VStack(alignment: .leading, spacing: 16) {
+ Text(content)
+ .textSelection(.enabled)
+ .lineLimit(isDescriptionExpanded ? nil : 5)
+ .font(.callout)
+ .foregroundStyle(Color(.surfaceVariant))
+ .background {
+ ViewThatFits(in: .vertical) {
+ Text(content)
+ .hidden()
+ // Just for receiving onAppear event if the description exceeds its line limit
+ Color.clear
+ .onAppear {
+ canBeExpanded = true
+ }
+ }
+ }
+ if canBeExpanded {
+ Button {
+ isDescriptionExpanded = true
+ canBeExpanded = false
+ } label: {
+ Text(String(localized: "TimeTableDetailReadMore", bundle: .module))
+ .foregroundStyle(Color(.primary))
+ .frame(width: 120, height: 40, alignment: .center)
+ .overlay {
+ Capsule()
+ .stroke(Color(.outline))
+ }
+ }
+ }
+ }
+ }
+}
+
+#Preview {
+ VStack {
+ SessionDescriptionView(content: SampleData.sessionDescription)
+ .padding(.horizontal, 16)
+ }
+ .background(Color(.background))
+}
diff --git a/app-ios/Sources/TimetableDetailFeature/TimetableDetailView.swift b/app-ios/Sources/TimetableDetailFeature/TimetableDetailView.swift
index e28e153f7..d78597c56 100644
--- a/app-ios/Sources/TimetableDetailFeature/TimetableDetailView.swift
+++ b/app-ios/Sources/TimetableDetailFeature/TimetableDetailView.swift
@@ -5,10 +5,173 @@ public struct TimetableDetailView: View {
private let store: StoreOf
public var body: some View {
- Text(store.title)
- .onAppear {
- store.send(.onAppear)
+ VStack {
+ ScrollView {
+ sessionDetail
+ .padding(.horizontal, 16)
+
+ Divider().background(Color(.outlineVariant))
+
+ targetUser
+ .padding(16)
+
+ Divider().background(Color(.outlineVariant))
+
+ speaker
+ .padding(16)
+
+ Divider().background(Color(.outlineVariant))
+
+ archive
+ .padding(16)
+ }
+
+ footer
+ }
+ .background(Color(.background))
+ .frame(maxWidth: .infinity)
+ }
+
+ var footer: some View {
+ HStack(spacing: 8) {
+ Button {
+ // do something
+ } label: {
+ Group {
+ Image(.icShare)
+ }
+ .frame(width: 40, height: 40)
+ }
+ Button {
+ // do something
+ } label: {
+ Group {
+ Image(.icAddCalendar)
+ }
+ .frame(width: 40, height: 40)
}
+ Spacer()
+ Button {
+ // do something
+ } label: {
+ Group {
+ Image(.icFavorite)
+ }
+ .frame(width: 56, height: 56)
+ .background(Color(.secondaryContainer))
+ .clipShape(RoundedRectangle(cornerRadius: 16))
+ }
+ }
+ .frame(height: 80)
+ .frame(maxWidth: .infinity)
+ .padding(.horizontal, 16)
+ .background(Color(.surfaceContainer))
+ }
+
+ @ViewBuilder var sessionDetail: some View {
+ VStack(alignment: .leading, spacing: 20) {
+ Text(SampleData.title)
+ .font(.title)
+ .foregroundStyle(Color(.surfaceVariant))
+ VStack(spacing: 16) {
+ InformationRow(
+ icon: Image(.icSchedule),
+ title: String(localized: "TimeTableDetailDate", bundle: .module),
+ content: SampleData.dateValue
+ )
+ InformationRow(
+ icon: Image(.icLocationOn),
+ title: String(localized: "TimeTableDetailLocation", bundle: .module),
+ content: SampleData.locationValue
+ )
+ InformationRow(
+ icon: Image(.icLanguage),
+ title: String(localized: "TimeTableDetailLanguage", bundle: .module),
+ content: SampleData.languageValue
+ )
+ InformationRow(
+ icon: Image(.icCategory),
+ title: String(localized: "TimeTableDetailCategory", bundle: .module),
+ content: SampleData.categoryValue
+ )
+ }
+ .padding(16)
+ .overlay(
+ RoundedRectangle(cornerRadius: 12)
+ .stroke(Color(.onSurface), lineWidth: 1)
+ )
+
+ SessionDescriptionView(content: SampleData.sessionDescription)
+ .padding(.bottom, 24)
+ }
+ }
+
+ @ViewBuilder var targetUser: some View {
+ VStack(alignment: .leading, spacing: 16) {
+ Text(String(localized: "TimeTableDetailApplicants", bundle: .module))
+ .font(.title3)
+ .foregroundStyle(Color(.surfaceVariant))
+
+ Text(SampleData.applicants)
+ .font(.callout)
+ .foregroundStyle(Color(.surfaceVariant))
+ }
+ }
+
+ @ViewBuilder var speaker: some View {
+ VStack(alignment: .leading, spacing: 16) {
+ Text(String(localized: "TimeTableDetailSpeaker", bundle: .module))
+ .font(.title3)
+ .foregroundStyle(Color(.surfaceVariant))
+
+ HStack {
+ Image(.avatar)
+ .padding(.trailing, 24)
+ Text(SampleData.name)
+ .font(.callout)
+ .foregroundStyle(Color(.onSurface))
+ Spacer()
+ }
+ }
+ }
+
+ @ViewBuilder var archive: some View {
+ VStack(alignment: .leading, spacing: 16) {
+ Text(String(localized: "TimeTableDetailArchive", bundle: .module))
+ .font(.title3)
+ .foregroundStyle(Color(.surfaceVariant))
+
+ HStack {
+ Button {
+ // do something
+ } label: {
+ VStack {
+ Label(
+ title: { Text(String(localized: "TimeTableDetailSlide", bundle: .module)).foregroundStyle(Color(.onPrimary)) },
+ icon: { Image(.icDocument) }
+ )
+ }
+ .frame(height: 40)
+ .frame(maxWidth: .infinity)
+ .background(Color(.button))
+ .clipShape(Capsule())
+ }
+ Button {
+ // do something
+ } label: {
+ VStack {
+ Label(
+ title: { Text(String(localized: "TimeTableDetailVideo", bundle: .module)).foregroundStyle(Color(.onPrimary)) },
+ icon: { Image(.icPlay) }
+ )
+ }
+ .frame(height: 40)
+ .frame(maxWidth: .infinity)
+ .background(Color(.button))
+ .clipShape(Capsule())
+ }
+ }
+ }
}
public init(store: StoreOf) {