Start Schedule development

This commit is contained in:
Shcherbatykh Oleg
2026-02-10 20:20:39 +03:00
parent 2688e44436
commit 04b8164eba
19 changed files with 214 additions and 79 deletions

View File

@@ -6,23 +6,16 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import ru.fincode.tsudesk.core.network.NetworkConstants
import ru.fincode.tsudesk.core.network.RetrofitProvider
import ru.fincode.tsudesk.core.network.NetworkModule
import ru.fincode.tsudesk.feature.schedule.data.remote.ScheduleApi
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
val okHttpClient = HttpClientProvider.provide()
val retrofit = RetrofitProvider.provide(
baseUrl = NetworkConstants.BASE_URL,
client = okHttpClient
)
val api = retrofit.create(ScheduleApi::class.java)
} }
} }

View File

@@ -1,10 +0,0 @@
package ru.fincode.tsudesk.core.network
object HttpClientProvider {
fun provide(): OkHttpClient =
OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.build()
}

View File

@@ -0,0 +1,34 @@
package ru.fincode.tsudesk.core.network
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import java.util.concurrent.TimeUnit
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
private const val TIMEOUT_SEC = 30L
@Provides
@Singleton
fun provideOkHttpClient(): OkHttpClient =
OkHttpClient.Builder()
.connectTimeout(TIMEOUT_SEC, TimeUnit.SECONDS)
.readTimeout(TIMEOUT_SEC, TimeUnit.SECONDS)
.writeTimeout(TIMEOUT_SEC, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build()
@Provides
fun provideRetrofit(
provider: RetrofitProvider,
client: OkHttpClient
): Retrofit = provider.process(NetworkConstants.BASE_URL, client)
}

View File

@@ -1,8 +1,11 @@
package ru.fincode.tsudesk.core.network package ru.fincode.tsudesk.core.network
object RetrofitProvider { import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.simplexml.SimpleXmlConverterFactory
fun provide(baseUrl: String, client: OkHttpClient): Retrofit = class RetrofitProvider {
fun process(baseUrl: String, client: OkHttpClient): Retrofit =
Retrofit.Builder() Retrofit.Builder()
.baseUrl(baseUrl) .baseUrl(baseUrl)
.client(client) .client(client)

View File

@@ -1,25 +0,0 @@
package ru.fincode.tsudesk.core.network.di
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import ru.fincode.tsudesk.core.network.HttpClientProvider
import ru.fincode.tsudesk.core.network.NetworkConstants
import ru.fincode.tsudesk.core.network.RetrofitProvider
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideOkHttpClient(): OkHttpClient =
HttpClientProvider.provide()
@Provides
@Singleton
fun provideRetrofit(client: OkHttpClient): Retrofit =
RetrofitProvider.provide(
baseUrl = NetworkConstants.BASE_URL,
client = client
)
}

View File

@@ -1,4 +1,21 @@
package ru.fincode.tsudesk.feature.schedule.data package ru.fincode.tsudesk.feature.schedule.data
class ScheduleRepositoryImpl { import ru.fincode.tsudesk.feature.schedule.data.datasource.ScheduleRemoteDataSource
} import ru.fincode.tsudesk.feature.schedule.data.mapper.ScheduleDtoToDomainMapper
import ru.fincode.tsudesk.feature.schedule.domain.model.Schedule
import ru.fincode.tsudesk.feature.schedule.domain.repository.ScheduleRepository
import javax.inject.Inject
class ScheduleRepositoryImpl @Inject constructor(
private val remote: ScheduleRemoteDataSource, private val mapper: ScheduleDtoToDomainMapper
) : ScheduleRepository {
override suspend fun loadScheduleByGroup(groupNumber: String): Schedule {
return mapper.map(remote.loadScheduleByGroup(groupNumber))
}
override suspend fun loadScheduleByTeacher(teacherName: String): Schedule {
return mapper.map(remote.loadScheduleByTeacher(teacherName))
}
}

View File

@@ -1,4 +1,10 @@
package ru.fincode.tsudesk.feature.schedule.data.datasource package ru.fincode.tsudesk.feature.schedule.data.datasource
class ScheduleLocalDataSource { import ru.fincode.tsudesk.feature.schedule.data.local.ScheduleEntity
} import ru.fincode.tsudesk.feature.schedule.data.remote.ScheduleDto
interface ScheduleLocalDataSource {
suspend fun getScheduleByGroup(groupNumber: String): ScheduleEntity?
suspend fun getScheduleByTeacherName(teacherName: String): ScheduleEntity?
suspend fun saveSchedule(entity: ScheduleEntity)
}

View File

@@ -1,4 +1,20 @@
package ru.fincode.tsudesk.feature.schedule.data.datasource package ru.fincode.tsudesk.feature.schedule.data.datasource
class ScheduleRemoteDataSource { import ru.fincode.tsudesk.feature.schedule.data.remote.ScheduleApi
} import ru.fincode.tsudesk.feature.schedule.data.remote.ScheduleDto
import ru.fincode.tsudesk.feature.schedule.data.remote.ScheduleXmlParser
import java.io.IOException
class ScheduleRemoteDataSource(
private val api: ScheduleApi, private val xmlParser: ScheduleXmlParser
) {
suspend fun loadScheduleByGroup(groupNumber: String): ScheduleDto {
val response = api.getScheduleByGroup(groupNumber)
return xmlParser.parse(response.body() ?: throw IOException("Response body is null"))
}
suspend fun loadScheduleByTeacher(name: String): ScheduleDto {
val response = api.getScheduleByTeacherName(name)
return xmlParser.parse(response.body() ?: throw IOException("Response body is null"))
}
}

View File

@@ -0,0 +1,20 @@
package ru.fincode.tsudesk.feature.schedule.data.datasource
import ru.fincode.tsudesk.feature.schedule.data.mapper.ScheduleDtoToDomainMapper
import ru.fincode.tsudesk.feature.schedule.domain.model.Schedule
import ru.fincode.tsudesk.feature.schedule.domain.repository.ScheduleRepository
import javax.inject.Inject
class ScheduleRepositoryImpl @Inject constructor(
private val remote: ScheduleRemoteDataSource,
private val mapper: ScheduleDtoToDomainMapper
) : ScheduleRepository {
override suspend fun loadScheduleByGroup(groupNumber: String): Schedule {
return mapper.map(remote.loadScheduleByGroup(groupNumber));
}
override suspend fun loadScheduleByTeacher(teacherName: String): Schedule {
return mapper.map(remote.loadScheduleByTeacher(teacherName));
}
}

View File

@@ -1,4 +1,23 @@
package ru.fincode.tsudesk.feature.schedule.data.mapper package ru.fincode.tsudesk.feature.schedule.data.mapper
import ru.fincode.tsudesk.feature.schedule.data.remote.ScheduleDto
import ru.fincode.tsudesk.feature.schedule.domain.model.Lesson
import ru.fincode.tsudesk.feature.schedule.domain.model.Schedule
class ScheduleDtoToDomainMapper { class ScheduleDtoToDomainMapper {
}
fun map(dto: ScheduleDto): Schedule =
Schedule(
lessons = dto.lessons.map { l ->
Lesson(
dayOfWeek = l.dayOfWeek,
dayName = l.dayName,
weekType = l.weekType,
time = l.time,
room = l.room,
subjectName = l.subjectName,
teacherName = l.teacherName
)
}
)
}

View File

@@ -1,4 +0,0 @@
package ru.fincode.tsudesk.feature.schedule.data.mapper
class ScheduleEntityToDomainMapper {
}

View File

@@ -1,4 +1,18 @@
package ru.fincode.tsudesk.feature.schedule.data.remote package ru.fincode.tsudesk.feature.schedule.data.remote
class ScheduleApi { import okhttp3.ResponseBody
} import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Query
interface ScheduleApi {
@GET("schedule")
suspend fun getScheduleByGroup(
@Query("group") groupNumber: String
): Response<ResponseBody>
@GET("schedule")
suspend fun getScheduleByTeacherName(
@Query("fio") teacherName: String
): Response<ResponseBody>
}

View File

@@ -1,4 +1,15 @@
package ru.fincode.tsudesk.feature.schedule.data.remote package ru.fincode.tsudesk.feature.schedule.data.remote
class ScheduleDto { data class ScheduleDto(
} val lessons: List<LessonDto>
)
data class LessonDto(
val dayOfWeek: String,
val dayName: String,
val time: String,
val room: String,
val subjectName: String,
val teacherName: String,
val weekType: Int
)

View File

@@ -1,4 +1,15 @@
package ru.fincode.tsudesk.feature.schedule.data.remote package ru.fincode.tsudesk.feature.schedule.data.remote
class ScheduleXmlParser { import okhttp3.ResponseBody
}
interface ScheduleXmlParser {
fun parse(body: ResponseBody): ScheduleDto
}
class ScheduleXmlParserImpl : ScheduleXmlParser {
override fun parse(body: ResponseBody): ScheduleDto {
val xml = body.string()
return ScheduleDto(lessons = emptyList())
}
}

View File

@@ -1,4 +0,0 @@
package ru.fincode.tsudesk.feature.schedule.domain.model
class Lesson {
}

View File

@@ -1,4 +1,17 @@
package ru.fincode.tsudesk.feature.schedule.domain.model package ru.fincode.tsudesk.feature.schedule.domain.model
class Schedule { data class Schedule(
} val lessons: List<Lesson>
)
data class Lesson(
val dayOfWeek: String,
val dayName: String,
val time: String,
val room: String,
val subjectName: String,
val teacherName: String,
val weekType: Int
)

View File

@@ -1,4 +0,0 @@
package ru.fincode.tsudesk.feature.schedule.domain.model
class ScheduleDay {
}

View File

@@ -3,5 +3,6 @@ package ru.fincode.tsudesk.feature.schedule.domain.repository
import ru.fincode.tsudesk.feature.schedule.domain.model.Schedule import ru.fincode.tsudesk.feature.schedule.domain.model.Schedule
interface ScheduleRepository { interface ScheduleRepository {
suspend fun getSchedule(groupId: String): Schedule suspend fun loadScheduleByGroup(groupNumber: String): Schedule
} suspend fun loadScheduleByTeacher(teacherName: String): Schedule
}

View File

@@ -0,0 +1,24 @@
package ru.fincode.tsudesk.feature.schedule.domain.repository
import ru.fincode.tsudesk.feature.schedule.data.datasource.ScheduleLocalDataSource
import ru.fincode.tsudesk.feature.schedule.data.datasource.ScheduleRemoteDataSource
import ru.fincode.tsudesk.feature.schedule.data.mapper.ScheduleDtoToDomainMapper
import ru.fincode.tsudesk.feature.schedule.domain.model.Schedule
import javax.inject.Inject
class ScheduleRepositoryImpl @Inject constructor(
private val remoteDataSource: ScheduleRemoteDataSource,
private val localDataSource: ScheduleLocalDataSource,
private val mapper: ScheduleDtoToDomainMapper
) : ScheduleRepository {
override suspend fun loadScheduleByGroup(groupNumber: String): Schedule {
val dto = remoteDataSource.loadScheduleByGroup(groupNumber)
return mapper.map(dto)
}
override suspend fun loadScheduleByTeacher(teacherName: String): Schedule {
val dto = remoteDataSource.loadScheduleByTeacher(teacherName)
return mapper.map(dto)
}
}