├── .idea ├── .name ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── compiler.xml ├── kotlinc.xml ├── vcs.xml ├── AndroidProjectSystem.xml ├── .gitignore ├── migrations.xml ├── detekt.xml ├── deploymentTargetSelector.xml ├── misc.xml ├── gradle.xml ├── runConfigurations.xml └── jarRepositories.xml ├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-ldpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-tvdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── xml │ │ │ │ ├── file_paths.xml │ │ │ │ ├── widget_large.xml │ │ │ │ ├── widget_small.xml │ │ │ │ ├── widget_medium.xml │ │ │ │ └── preferences.xml │ │ │ ├── drawable │ │ │ │ ├── widget_preview_large.png │ │ │ │ ├── widget_preview_small.png │ │ │ │ ├── widget_preview_meduim.png │ │ │ │ ├── widget_divider.xml │ │ │ │ ├── splash.xml │ │ │ │ ├── widget_rounded_bg.xml │ │ │ │ ├── ic_error.xml │ │ │ │ ├── ic_mail_outline.xml │ │ │ │ ├── widget_rounded_bg_stroke.xml │ │ │ │ ├── ic_event.xml │ │ │ │ ├── ic_place.xml │ │ │ │ ├── widget_inner_shadow_gradient_dark_vertical.xml │ │ │ │ ├── widget_inner_shadow_gradient_light_horizontal.xml │ │ │ │ ├── widget_inner_shadow_gradient_light_vertical.xml │ │ │ │ ├── widget_inner_shadow_gradient_dark_horizontal.xml │ │ │ │ ├── ic_refresh.xml │ │ │ │ ├── ic_alarm.xml │ │ │ │ ├── ic_clock.xml │ │ │ │ ├── ic_source.xml │ │ │ │ ├── ic_twitter.xml │ │ │ │ ├── ic_github.xml │ │ │ │ ├── ic_web.xml │ │ │ │ ├── ic_icon.xml │ │ │ │ ├── ic_icon_small.xml │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── values │ │ │ │ ├── dimens.xml │ │ │ │ ├── styles.xml │ │ │ │ ├── colors.xml │ │ │ │ └── strings.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── layout │ │ │ │ ├── activity_settings.xml │ │ │ │ ├── activity_main.xml │ │ │ │ ├── fragment_sub_webview.xml │ │ │ │ ├── widget_period_item.xml │ │ │ │ ├── widget_course_item_with_header.xml │ │ │ │ ├── widget_course_item.xml │ │ │ │ ├── widget_error.xml │ │ │ │ ├── widget_small.xml │ │ │ │ ├── widget_large.xml │ │ │ │ └── widget_medium.xml │ │ │ ├── values-night │ │ │ │ ├── styles.xml │ │ │ │ └── colors.xml │ │ │ └── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ ├── java │ │ │ └── net │ │ │ │ └── twinte │ │ │ │ ├── android │ │ │ │ ├── datastore │ │ │ │ │ ├── user │ │ │ │ │ │ ├── UserDataStore.kt │ │ │ │ │ │ └── TwinteBackendUserDataStore.kt │ │ │ │ │ ├── schedulenotification │ │ │ │ │ │ ├── ScheduleNotificationDataStore.kt │ │ │ │ │ │ └── SharedPreferencesScheduleNotificationDataStore.kt │ │ │ │ │ ├── resetcookiesforsamesite │ │ │ │ │ │ ├── ResetCookiesForSameSiteDataStore.kt │ │ │ │ │ │ └── ResetCookiesForSameSiteDataStoreImpl.kt │ │ │ │ │ └── schedule │ │ │ │ │ │ ├── ScheduleDataStore.kt │ │ │ │ │ │ └── SharedPreferencesScheduleDataStore.kt │ │ │ │ ├── MainApplication.kt │ │ │ │ ├── widget │ │ │ │ │ ├── WidgetCourseViewModel.kt │ │ │ │ │ ├── SmallWidgetProvider.kt │ │ │ │ │ ├── Utils.kt │ │ │ │ │ ├── LargeWidgetProvider.kt │ │ │ │ │ └── MediumWidgetProvider.kt │ │ │ │ ├── network │ │ │ │ │ ├── serversettings │ │ │ │ │ │ ├── ServerSettings.kt │ │ │ │ │ │ └── ProductionServerSettings.kt │ │ │ │ │ ├── TwinteBackendHttpClient.kt │ │ │ │ │ ├── V4ApiClient.kt │ │ │ │ │ ├── QueryParameters.kt │ │ │ │ │ ├── V4ApiClientImpl.kt │ │ │ │ │ └── TwinteBackendHttpClientImpl.kt │ │ │ │ ├── model │ │ │ │ │ ├── Format.kt │ │ │ │ │ ├── EventType.kt │ │ │ │ │ ├── Day.kt │ │ │ │ │ ├── Module.kt │ │ │ │ │ └── Timetable.kt │ │ │ │ ├── Network.kt │ │ │ │ ├── mapping │ │ │ │ │ └── proto │ │ │ │ │ │ ├── EventTypeMapper.kt │ │ │ │ │ │ ├── ModuleMapper.kt │ │ │ │ │ │ ├── EventMapper.kt │ │ │ │ │ │ ├── ScheduleMapper.kt │ │ │ │ │ │ ├── RegisteredCourseMapper.kt │ │ │ │ │ │ └── GetByDateResponseMapper.kt │ │ │ │ ├── ShareScreen.kt │ │ │ │ ├── SettingsActivity.kt │ │ │ │ ├── MainApplicationModule.kt │ │ │ │ ├── work │ │ │ │ │ ├── UpdateScheduleWorker.kt │ │ │ │ │ └── ScheduleNotifier.kt │ │ │ │ └── SubWebViewFragment.kt │ │ │ │ └── api │ │ │ │ ├── unified │ │ │ │ └── v1 │ │ │ │ │ ├── UnifiedServiceClientInterface.kt │ │ │ │ │ └── UnifiedServiceClient.kt │ │ │ │ ├── announcement │ │ │ │ └── v1 │ │ │ │ │ ├── AnnouncementServiceClientInterface.kt │ │ │ │ │ └── AnnouncementServiceClient.kt │ │ │ │ ├── schoolcalendar │ │ │ │ └── v1 │ │ │ │ │ ├── SchoolCalendarServiceClientInterface.kt │ │ │ │ │ └── SchoolCalendarServiceClient.kt │ │ │ │ ├── auth │ │ │ │ └── v1 │ │ │ │ │ ├── AuthServiceClientInterface.kt │ │ │ │ │ └── AuthServiceClient.kt │ │ │ │ ├── donation │ │ │ │ └── v1 │ │ │ │ │ ├── DonationServiceClientInterface.kt │ │ │ │ │ └── DonationServiceClient.kt │ │ │ │ └── timetable │ │ │ │ └── v1 │ │ │ │ ├── TimetableServiceClientInterface.kt │ │ │ │ └── TimetableServiceClient.kt │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── net │ │ │ └── twinte │ │ │ └── android │ │ │ ├── ExampleUnitTest.kt │ │ │ └── datastore │ │ │ ├── user │ │ │ └── TwinteBackendUserDataStoreTest.kt │ │ │ └── schedule │ │ │ └── SharedPreferencesScheduleDataStoreTest.kt │ └── androidTest │ │ └── java │ │ └── net │ │ └── twinte │ │ └── android │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle.kts ├── .gitattributes ├── settings.gradle.kts ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── libs.versions.toml ├── buf.gen.yml ├── .gitignore ├── README.md ├── .github └── workflows │ └── android.yml ├── gradle.properties ├── gradlew.bat ├── config └── detekt │ └── detekt.yml └── gradlew /.idea/.name: -------------------------------------------------------------------------------- 1 | TwinteAndroid -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | app/src/main/java/net/twinte/api/** linguist-generated=true 2 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | include(":app") 2 | rootProject.name = "TwinteAndroid" 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/app/src/main/res/mipmap-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-tvdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/app/src/main/res/mipmap-tvdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/xml/file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/widget_preview_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/app/src/main/res/drawable/widget_preview_large.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/widget_preview_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/app/src/main/res/drawable/widget_preview_small.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/widget_preview_meduim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/app/src/main/res/drawable/widget_preview_meduim.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twin-te/twinte-android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 16dp 3 | 21.67dp 4 | 5 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/datastore/user/UserDataStore.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.datastore.user 2 | 3 | interface UserDataStore { 4 | suspend fun validateGoogleIdToken(idToken: String): Boolean 5 | } 6 | -------------------------------------------------------------------------------- /buf.gen.yml: -------------------------------------------------------------------------------- 1 | version: v2 2 | plugins: 3 | - remote: buf.build/protocolbuffers/java:v30.2 4 | out: app/src/main/java 5 | opt: lite 6 | - remote: buf.build/connectrpc/kotlin 7 | out: app/src/main/java 8 | opt: lite 9 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/MainApplication.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android 2 | 3 | import android.app.Application 4 | import dagger.hilt.android.HiltAndroidApp 5 | 6 | @HiltAndroidApp 7 | class MainApplication : Application() 8 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/datastore/schedulenotification/ScheduleNotificationDataStore.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.datastore.schedulenotification 2 | 3 | interface ScheduleNotificationDataStore { 4 | fun schedule() 5 | } 6 | -------------------------------------------------------------------------------- /.idea/AndroidProjectSystem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/widget/WidgetCourseViewModel.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.widget 2 | 3 | /** 4 | * ウィジットで表示される授業のVM 5 | */ 6 | data class WidgetCourseViewModel(val name: String, val room: String, val time: String, val id: String?) 7 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/network/serversettings/ServerSettings.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.network.serversettings 2 | 3 | interface ServerSettings { 4 | val twinteBackendApiEndpointScheme: String 5 | val twinteBackendApiEndpointHost: String 6 | } 7 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | .idea/dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | 10 | deploymentTargetDropDown.xml 11 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/network/TwinteBackendHttpClient.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.network 2 | 3 | import okhttp3.Response 4 | 5 | interface TwinteBackendHttpClient { 6 | suspend fun get(path: String, params: QueryParameters = QueryParameters()): Response 7 | } 8 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Apr 12 16:51:02 JST 2021 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | *.jks 15 | .cxx 16 | -------------------------------------------------------------------------------- /.idea/migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.idea/detekt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/network/serversettings/ProductionServerSettings.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.network.serversettings 2 | 3 | class ProductionServerSettings : ServerSettings { 4 | override val twinteBackendApiEndpointScheme: String = "https" 5 | override val twinteBackendApiEndpointHost: String = "app.twinte.net" 6 | } 7 | -------------------------------------------------------------------------------- /.idea/deploymentTargetSelector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # twinte-android 2 | 3 | Twin:teのAndroid版ネイティブアプリ 4 | 5 | ## code generation 6 | 7 | 1. https://buf.build/docs/cli/installation/ を参考にBuf CLIをインストールしてください 8 | 2. https://github.com/twin-te/twin-te をクローンします(ここでは `/path/to/twin-te` にクローンしたものとする) 9 | 3. リポジトリのルートで以下のコマンドを実行するとAPI用のコードが生成されます 10 | 11 | ```shell 12 | buf generate --template ./buf.gen.yml 13 | ``` 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/widget_divider.xml: -------------------------------------------------------------------------------- 1 | 3 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 9 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/widget_rounded_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/xml/widget_large.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/xml/widget_small.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/xml/widget_medium.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/network/V4ApiClient.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.network 2 | 3 | import net.twinte.api.schoolcalendar.v1.SchoolCalendarServiceClient 4 | import net.twinte.api.timetable.v1.TimetableServiceClient 5 | import net.twinte.api.unified.v1.UnifiedServiceClient 6 | 7 | interface V4ApiClient { 8 | val timetable: TimetableServiceClient 9 | val schoolCalendar: SchoolCalendarServiceClient 10 | val unified: UnifiedServiceClient 11 | } 12 | -------------------------------------------------------------------------------- /app/src/test/java/net/twinte/android/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android 2 | 3 | import org.junit.Assert.assertEquals 4 | import org.junit.Test 5 | 6 | /** 7 | * Example local unit test, which will execute on the development machine (host). 8 | * 9 | * See [testing documentation](http://d.android.com/tools/testing). 10 | */ 11 | class ExampleUnitTest { 12 | @Test 13 | fun addition_isCorrect() { 14 | assertEquals(4, 2 + 2) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/model/Format.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.model 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class Format(val f: String) { 6 | @SerializedName("Asynchronous") 7 | OnlineAsynchronous("オンデマンド"), 8 | 9 | @SerializedName("Synchronous") 10 | OnlineSynchronous("同時双方向"), 11 | 12 | @SerializedName("FaceToFace") 13 | FaceToFace("対面"), 14 | 15 | @SerializedName("Others") 16 | Others("その他"), 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/network/QueryParameters.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.network 2 | 3 | /** 4 | * リクエスト送信時に指定するクエリパラメータを保持するためのデータ構造 5 | */ 6 | typealias QueryParameters = MutableMap 7 | 8 | /** 9 | * 空のクエリパラメータ 10 | */ 11 | fun QueryParameters(): QueryParameters = mutableMapOf() 12 | 13 | /** 14 | * クエリパラメータを指定するための shorthand 用関数 15 | */ 16 | fun params(block: QueryParameters.() -> Unit): QueryParameters = 17 | QueryParameters().apply(block) 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_error.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/datastore/resetcookiesforsamesite/ResetCookiesForSameSiteDataStore.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.datastore.resetcookiesforsamesite 2 | 3 | /** 4 | * ref: https://github.com/twin-te/twinte-android/issues/44 5 | * SameSite 属性が付与されていない twinte_session Cookie があるとき、 6 | * lTWINS からの時間割インポートに失敗するため、一度 WebView が利用できる Cookie を 7 | * すべて削除し、再度 Twin:te の認証を行わせるために利用される DataStore 8 | */ 9 | interface ResetCookiesForSameSiteDataStore { 10 | var shouldResetCookiesForSameSite: Boolean 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_mail_outline.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/model/EventType.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.model 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class EventType(val e: String) { 6 | @SerializedName("Holiday") 7 | Holiday("休日"), 8 | 9 | @SerializedName("PublicHoliday") 10 | PublicHoliday("祝日"), 11 | 12 | @SerializedName("Exam") 13 | Exam("試験"), 14 | 15 | @SerializedName("SubstituteDay") 16 | SubstituteDay("振替授業日"), 17 | 18 | @SerializedName("Other") 19 | Other("その他"), 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/widget_rounded_bg_stroke.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_event.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/datastore/schedule/ScheduleDataStore.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.datastore.schedule 2 | 3 | import net.twinte.android.model.Timetable 4 | import java.util.Calendar 5 | import java.util.Date 6 | 7 | interface ScheduleDataStore { 8 | suspend fun update( 9 | calendar: Array = arrayOf( 10 | Calendar.getInstance().time, 11 | Calendar.getInstance().apply { add(Calendar.DATE, 1) }.time, 12 | ), 13 | ) 14 | 15 | suspend fun getSchedule(date: Date): Timetable? 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_place.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/Network.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android 2 | 3 | import android.net.Uri 4 | import net.twinte.android.network.serversettings.ServerSettings 5 | 6 | fun twinteUrlBuilder( 7 | serverSettings: ServerSettings, 8 | ): Uri.Builder = Uri 9 | .Builder() 10 | .scheme(serverSettings.twinteBackendApiEndpointScheme) 11 | .path(serverSettings.twinteBackendApiEndpointHost) 12 | 13 | fun Uri.Builder.buildUrl() = build().toString() 14 | class NotLoggedInException(cause: Throwable? = null) : Throwable("Not Logged in", cause) 15 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/model/Day.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.model 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class Day(val d: String) { 6 | @SerializedName("Sun") 7 | Sun("日"), 8 | 9 | @SerializedName("Mon") 10 | Mon("月"), 11 | 12 | @SerializedName("Tue") 13 | Tue("火"), 14 | 15 | @SerializedName("Wed") 16 | Wed("水"), 17 | 18 | @SerializedName("Thu") 19 | Thu("木"), 20 | 21 | @SerializedName("Fri") 22 | Fri("金"), 23 | 24 | @SerializedName("Sat") 25 | Sat("土"), 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/widget_inner_shadow_gradient_dark_vertical.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/widget_inner_shadow_gradient_light_horizontal.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/widget_inner_shadow_gradient_light_vertical.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/widget_inner_shadow_gradient_dark_horizontal.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_refresh.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_alarm.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_clock.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_sub_webview.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/androidTest/java/net/twinte/android/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android 2 | 3 | import androidx.test.ext.junit.runners.AndroidJUnit4 4 | import androidx.test.platform.app.InstrumentationRegistry 5 | import org.junit.Assert.* 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | /** 10 | * Instrumented test, which will execute on an Android device. 11 | * 12 | * See [testing documentation](http://d.android.com/tools/testing). 13 | */ 14 | @RunWith(AndroidJUnit4::class) 15 | class ExampleInstrumentedTest { 16 | @Test 17 | fun useAppContext() { 18 | // Context of the app under test. 19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 20 | assertEquals("net.twinte.android", appContext.packageName) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/mapping/proto/EventTypeMapper.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.mapping.proto 2 | 3 | import net.twinte.android.model.EventType as ModelEventType 4 | import net.twinte.api.schoolcalendar.v1.Type.EventType as ProtoEventType 5 | 6 | internal fun ProtoEventType.asModel(): ModelEventType = when (this) { 7 | ProtoEventType.EVENT_TYPE_UNSPECIFIED -> ModelEventType.Other 8 | ProtoEventType.EVENT_TYPE_HOLIDAY -> ModelEventType.Holiday 9 | ProtoEventType.EVENT_TYPE_PUBLIC_HOLIDAY -> ModelEventType.PublicHoliday 10 | ProtoEventType.EVENT_TYPE_EXAM -> ModelEventType.Exam 11 | ProtoEventType.EVENT_TYPE_SUBSTITUTE_DAY -> ModelEventType.SubstituteDay 12 | ProtoEventType.EVENT_TYPE_OTHER -> ModelEventType.Other 13 | ProtoEventType.UNRECOGNIZED -> ModelEventType.Other 14 | } 15 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/datastore/user/TwinteBackendUserDataStore.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.datastore.user 2 | 3 | import kotlinx.coroutines.Dispatchers 4 | import kotlinx.coroutines.withContext 5 | import net.twinte.android.network.TwinteBackendHttpClient 6 | import net.twinte.android.network.params 7 | import javax.inject.Inject 8 | 9 | class TwinteBackendUserDataStore @Inject constructor( 10 | private val twinteBackendHttpClient: TwinteBackendHttpClient, 11 | ) : UserDataStore { 12 | override suspend fun validateGoogleIdToken(idToken: String): Boolean = withContext(Dispatchers.IO) { 13 | val res = twinteBackendHttpClient.get( 14 | "/auth/v4/google/idToken", 15 | params { 16 | put("token", idToken) 17 | }, 18 | ) 19 | res.isSuccessful 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/model/Module.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.model 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class Module(val m: String) { 6 | @SerializedName("SpringA") 7 | SpringA("春A"), 8 | 9 | @SerializedName("SpringB") 10 | SpringB("春B"), 11 | 12 | @SerializedName("SpringC") 13 | SpringC("春C"), 14 | 15 | @SerializedName("FallA") 16 | FallA("秋A"), 17 | 18 | @SerializedName("FallB") 19 | FallB("秋B"), 20 | 21 | @SerializedName("FallC") 22 | FallC("秋C"), 23 | 24 | @SerializedName("SummerVacation") 25 | SummerVacation("夏季休業中"), 26 | 27 | @SerializedName("SpringVacation") 28 | SpringVacation("春季休業中"), 29 | 30 | @SerializedName("Annual") 31 | Annual("通年"), 32 | 33 | @SerializedName("Unknown") 34 | Unknown("不明"), 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/widget_period_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_source.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/api/unified/v1/UnifiedServiceClientInterface.kt: -------------------------------------------------------------------------------- 1 | // Code generated by connect-kotlin. DO NOT EDIT. 2 | // 3 | // Source: unified/v1/service.proto 4 | // 5 | package net.twinte.api.unified.v1 6 | 7 | import com.connectrpc.Headers 8 | import com.connectrpc.ResponseMessage 9 | 10 | /** 11 | * The following error codes are not stated explicitly in the each rpc, but may be returned. 12 | * - shared.InvalidArgument 13 | * - shared.Unauthenticated 14 | * - shared.Unauthorized 15 | */ 16 | public interface UnifiedServiceClientInterface { 17 | /** 18 | * GetByDate returns the resources related to the given date. 19 | * Only registered courses which will be held on the given date will be returned. 20 | */ 21 | public suspend fun getByDate(request: Service.GetByDateRequest, headers: Headers = emptyMap()): ResponseMessage 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/mapping/proto/ModuleMapper.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.mapping.proto 2 | 3 | import net.twinte.android.model.Module as ModelModule 4 | import net.twinte.api.timetable.v1.Type.Module as ProtoModule 5 | 6 | internal fun ProtoModule.asModel(): ModelModule = when (this) { 7 | ProtoModule.MODULE_UNSPECIFIED -> ModelModule.Unknown 8 | ProtoModule.MODULE_SPRING_A -> ModelModule.SpringA 9 | ProtoModule.MODULE_SPRING_B -> ModelModule.SpringB 10 | ProtoModule.MODULE_SPRING_C -> ModelModule.SpringC 11 | ProtoModule.MODULE_SUMMER_VACATION -> ModelModule.SummerVacation 12 | ProtoModule.MODULE_FALL_A -> ModelModule.FallA 13 | ProtoModule.MODULE_FALL_B -> ModelModule.FallB 14 | ProtoModule.MODULE_FALL_C -> ModelModule.SpringC 15 | ProtoModule.MODULE_SPRING_VACATION -> ModelModule.SpringVacation 16 | ProtoModule.UNRECOGNIZED -> ModelModule.Unknown 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/api/announcement/v1/AnnouncementServiceClientInterface.kt: -------------------------------------------------------------------------------- 1 | // Code generated by connect-kotlin. DO NOT EDIT. 2 | // 3 | // Source: announcement/v1/service.proto 4 | // 5 | package net.twinte.api.announcement.v1 6 | 7 | import com.connectrpc.Headers 8 | import com.connectrpc.ResponseMessage 9 | 10 | /** 11 | * The following error codes are not stated explicitly in the each rpc, but may be returned. 12 | * - shared.InvalidArgument 13 | * - shared.Unauthenticated 14 | * - shared.Unauthorized 15 | */ 16 | public interface AnnouncementServiceClientInterface { 17 | public suspend fun listAnnouncements(request: Service.ListAnnouncementsRequest, headers: Headers = emptyMap()): ResponseMessage 18 | 19 | public suspend fun readAnnouncements(request: Service.ReadAnnouncementsRequest, headers: Headers = emptyMap()): ResponseMessage 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/api/schoolcalendar/v1/SchoolCalendarServiceClientInterface.kt: -------------------------------------------------------------------------------- 1 | // Code generated by connect-kotlin. DO NOT EDIT. 2 | // 3 | // Source: schoolcalendar/v1/service.proto 4 | // 5 | package net.twinte.api.schoolcalendar.v1 6 | 7 | import com.connectrpc.Headers 8 | import com.connectrpc.ResponseMessage 9 | 10 | /** 11 | * The following error codes are not stated explicitly in the each rpc, but may be returned. 12 | * - shared.InvalidArgument 13 | * - shared.Unauthenticated 14 | * - shared.Unauthorized 15 | */ 16 | public interface SchoolCalendarServiceClientInterface { 17 | public suspend fun listEventsByDate(request: Service.ListEventsByDateRequest, headers: Headers = emptyMap()): ResponseMessage 18 | 19 | public suspend fun getModuleByDate(request: Service.GetModuleByDateRequest, headers: Headers = emptyMap()): ResponseMessage 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_twitter.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/mapping/proto/EventMapper.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.mapping.proto 2 | 3 | import net.twinte.android.model.Day 4 | import net.twinte.api.shared.Type.Weekday 5 | import net.twinte.android.model.Timetable.Event as ModuleEvent 6 | import net.twinte.api.schoolcalendar.v1.Type.Event as ProtoEvent 7 | 8 | internal fun ProtoEvent.asModel(): ModuleEvent = 9 | ModuleEvent( 10 | date = date.value, 11 | eventType = type.asModel(), 12 | description = description, 13 | changeTo = changeTo.asModel(), 14 | ) 15 | 16 | internal fun Weekday.asModel(): Day? = when (this) { 17 | Weekday.WEEKDAY_SUNDAY -> Day.Sun 18 | Weekday.WEEKDAY_MONDAY -> Day.Mon 19 | Weekday.WEEKDAY_TUESDAY -> Day.Tue 20 | Weekday.WEEKDAY_WEDNESDAY -> Day.Wed 21 | Weekday.WEEKDAY_THURSDAY -> Day.Thu 22 | Weekday.WEEKDAY_FRIDAY -> Day.Fri 23 | Weekday.WEEKDAY_SATURDAY -> Day.Sat 24 | else -> null 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/mapping/proto/ScheduleMapper.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.mapping.proto 2 | 3 | import net.twinte.android.model.Day as ModelDay 4 | import net.twinte.android.model.Timetable.Course.Schedule as ModelSchedule 5 | import net.twinte.api.timetable.v1.Type.Day as ProtoDay 6 | import net.twinte.api.timetable.v1.Type.Schedule as ProtoSchedule 7 | 8 | internal fun ProtoSchedule.asModel(): ModelSchedule = 9 | ModelSchedule( 10 | module = module.asModel(), 11 | day = day.asModel() ?: ModelDay.Sun, // TODO: Fix 12 | period = period, 13 | room = locations, 14 | ) 15 | 16 | internal fun ProtoDay.asModel(): ModelDay? = when (this) { 17 | ProtoDay.DAY_SUN -> ModelDay.Sun 18 | ProtoDay.DAY_MON -> ModelDay.Mon 19 | ProtoDay.DAY_TUE -> ModelDay.Tue 20 | ProtoDay.DAY_WED -> ModelDay.Wed 21 | ProtoDay.DAY_THU -> ModelDay.Thu 22 | ProtoDay.DAY_FRI -> ModelDay.Fri 23 | ProtoDay.DAY_SAT -> ModelDay.Sat 24 | else -> null 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #1e2430 4 | 5 | @color/n_colorPrimary 6 | @color/n_widget_text_main 7 | @color/n_widget_text_sub 8 | @color/n_widget_text_disabled 9 | @color/n_widget_text_danger 10 | 11 | #1B202D 12 | #03050B 13 | #1B202C 14 | #141821 15 | #00141821 16 | #131720 17 | #00131720 18 | #141A22 19 | #1C2734 20 | 21 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/api/auth/v1/AuthServiceClientInterface.kt: -------------------------------------------------------------------------------- 1 | // Code generated by connect-kotlin. DO NOT EDIT. 2 | // 3 | // Source: auth/v1/service.proto 4 | // 5 | package net.twinte.api.auth.v1 6 | 7 | import com.connectrpc.Headers 8 | import com.connectrpc.ResponseMessage 9 | 10 | /** 11 | * The following error codes are not stated explicitly in the each rpc, but may be returned. 12 | * - shared.InvalidArgument 13 | * - shared.Unauthenticated 14 | * - shared.Unauthorized 15 | */ 16 | public interface AuthServiceClientInterface { 17 | public suspend fun getMe(request: Service.GetMeRequest, headers: Headers = emptyMap()): ResponseMessage 18 | 19 | public suspend fun deleteUserAuthentication(request: Service.DeleteUserAuthenticationRequest, headers: Headers = emptyMap()): ResponseMessage 20 | 21 | public suspend fun deleteAccount(request: Service.DeleteAccountRequest, headers: Headers = emptyMap()): ResponseMessage 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_github.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/java/net/twinte/android/datastore/resetcookiesforsamesite/ResetCookiesForSameSiteDataStoreImpl.kt: -------------------------------------------------------------------------------- 1 | package net.twinte.android.datastore.resetcookiesforsamesite 2 | 3 | import android.content.Context 4 | import androidx.core.content.edit 5 | import dagger.hilt.android.qualifiers.ApplicationContext 6 | import javax.inject.Inject 7 | 8 | class ResetCookiesForSameSiteDataStoreImpl @Inject constructor( 9 | @ApplicationContext private val context: Context, 10 | ) : ResetCookiesForSameSiteDataStore { 11 | private val preferences = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE) 12 | 13 | override var shouldResetCookiesForSameSite: Boolean 14 | get() = preferences.getBoolean(KEY_RESET_COOKIES_FOR_SAMESITE, true) 15 | set(value) { 16 | preferences.edit { 17 | putBoolean(KEY_RESET_COOKIES_FOR_SAMESITE, value) 18 | } 19 | } 20 | 21 | companion object { 22 | const val FILE_NAME = "reset_cookies_For_samesite" 23 | private const val KEY_RESET_COOKIES_FOR_SAMESITE = "resetCookiesForSameSite" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_web.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | - develop 6 | pull_request: 7 | branches: 8 | - master 9 | - develop 10 | 11 | jobs: 12 | lint: 13 | runs-on: ubuntu-22.04 14 | timeout-minutes: 30 15 | steps: 16 | - uses: actions/checkout@v3 17 | - uses: actions/setup-java@v3 18 | with: 19 | distribution: zulu 20 | java-version: '17' 21 | cache: 'gradle' 22 | - name: Lint 23 | run: ./gradlew detekt lint 24 | test: 25 | runs-on: ubuntu-22.04 26 | timeout-minutes: 30 27 | steps: 28 | - uses: actions/checkout@v3 29 | - uses: actions/setup-java@v3 30 | with: 31 | distribution: zulu 32 | java-version: '17' 33 | cache: 'gradle' 34 | - name: Run tests 35 | run: ./gradlew testDebug --continue 36 | assemble: 37 | runs-on: ubuntu-22.04 38 | timeout-minutes: 30 39 | steps: 40 | - uses: actions/checkout@v3 41 | - uses: actions/setup-java@v3 42 | with: 43 | distribution: zulu 44 | java-version: '17' 45 | cache: 'gradle' 46 | - name: Build APK 47 | run: ./gradlew assemble 48 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 15 | 19 | 22 |