Very Very barebones wearos skeleton
|
|
@ -129,10 +129,6 @@
|
|||
<string name="usernames_party">%s\'s Party</string>
|
||||
<string name="chat">Chat</string>
|
||||
<string name="members">Members</string>
|
||||
<string name="habits">Habits</string>
|
||||
<string name="dailies">Dailies</string>
|
||||
<string name="todos">To Do\'s</string>
|
||||
<string name="rewards">Rewards</string>
|
||||
<string name="yes">Yes</string>
|
||||
<string name="no">No</string>
|
||||
<string name="discard">Discard</string>
|
||||
|
|
@ -603,7 +599,6 @@
|
|||
<string name="come_back_soon">Come back soon!</string>
|
||||
<string name="level">Level</string>
|
||||
<string name="streak_label">21-Day Streaks</string>
|
||||
<string name="stats">Stats</string>
|
||||
<string name="fix_character_description">If you’ve encountered a bug or made a mistake that unfairly changed your character, you can manually correct those values here.</string>
|
||||
<string name="fix_character_values">Fix Character Values</string>
|
||||
<string name="saving">Saving</string>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 400 B After Width: | Height: | Size: 400 B |
|
Before Width: | Height: | Size: 412 B After Width: | Height: | Size: 412 B |
|
Before Width: | Height: | Size: 580 B After Width: | Height: | Size: 580 B |
|
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 512 B |
|
Before Width: | Height: | Size: 266 B After Width: | Height: | Size: 266 B |
|
Before Width: | Height: | Size: 236 B After Width: | Height: | Size: 236 B |
|
Before Width: | Height: | Size: 280 B After Width: | Height: | Size: 280 B |
|
Before Width: | Height: | Size: 584 B After Width: | Height: | Size: 584 B |
|
Before Width: | Height: | Size: 330 B After Width: | Height: | Size: 330 B |
|
Before Width: | Height: | Size: 348 B After Width: | Height: | Size: 348 B |
|
Before Width: | Height: | Size: 450 B After Width: | Height: | Size: 450 B |
|
Before Width: | Height: | Size: 420 B After Width: | Height: | Size: 420 B |
|
Before Width: | Height: | Size: 164 B After Width: | Height: | Size: 164 B |
|
Before Width: | Height: | Size: 191 B After Width: | Height: | Size: 191 B |
|
Before Width: | Height: | Size: 134 B After Width: | Height: | Size: 134 B |
|
Before Width: | Height: | Size: 171 B After Width: | Height: | Size: 171 B |
|
Before Width: | Height: | Size: 182 B After Width: | Height: | Size: 182 B |
|
Before Width: | Height: | Size: 216 B After Width: | Height: | Size: 216 B |
|
Before Width: | Height: | Size: 382 B After Width: | Height: | Size: 382 B |
|
Before Width: | Height: | Size: 925 B After Width: | Height: | Size: 925 B |
|
Before Width: | Height: | Size: 466 B After Width: | Height: | Size: 466 B |
|
Before Width: | Height: | Size: 474 B After Width: | Height: | Size: 474 B |
|
Before Width: | Height: | Size: 676 B After Width: | Height: | Size: 676 B |
|
Before Width: | Height: | Size: 626 B After Width: | Height: | Size: 626 B |
|
Before Width: | Height: | Size: 238 B After Width: | Height: | Size: 238 B |
|
Before Width: | Height: | Size: 274 B After Width: | Height: | Size: 274 B |
|
Before Width: | Height: | Size: 226 B After Width: | Height: | Size: 226 B |
|
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 282 B |
|
Before Width: | Height: | Size: 304 B After Width: | Height: | Size: 304 B |
|
Before Width: | Height: | Size: 402 B After Width: | Height: | Size: 402 B |
|
Before Width: | Height: | Size: 748 B After Width: | Height: | Size: 748 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 560 B After Width: | Height: | Size: 560 B |
|
Before Width: | Height: | Size: 552 B After Width: | Height: | Size: 552 B |
|
Before Width: | Height: | Size: 848 B After Width: | Height: | Size: 848 B |
|
Before Width: | Height: | Size: 814 B After Width: | Height: | Size: 814 B |
|
Before Width: | Height: | Size: 328 B After Width: | Height: | Size: 328 B |
|
Before Width: | Height: | Size: 368 B After Width: | Height: | Size: 368 B |
|
Before Width: | Height: | Size: 312 B After Width: | Height: | Size: 312 B |
|
Before Width: | Height: | Size: 372 B After Width: | Height: | Size: 372 B |
|
Before Width: | Height: | Size: 420 B After Width: | Height: | Size: 420 B |
|
Before Width: | Height: | Size: 559 B After Width: | Height: | Size: 559 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
|
@ -15,4 +15,10 @@
|
|||
<string name="easy">Easy</string>
|
||||
<string name="medium">Medium</string>
|
||||
<string name="hard">Hard</string>
|
||||
<string name="habits">Habits</string>
|
||||
<string name="dailies">Dailies</string>
|
||||
<string name="todos">To Do\'s</string>
|
||||
<string name="rewards">Rewards</string>
|
||||
<string name="stats">Stats</string>
|
||||
|
||||
</resources>
|
||||
|
|
@ -30,14 +30,13 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
implementation 'com.google.android.gms:play-services-wearable:17.1.0'
|
||||
implementation 'androidx.percentlayout:percentlayout:1.0.0'
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||
implementation 'androidx.wear:wear:1.2.0'
|
||||
|
||||
implementation "androidx.wear:wear-input:1.1.0"
|
||||
//Networking
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
|
||||
|
|
@ -47,6 +46,7 @@ dependencies {
|
|||
}
|
||||
implementation('com.squareup.retrofit2:converter-moshi:2.9.0')
|
||||
implementation("com.squareup.moshi:moshi-kotlin:1.13.0")
|
||||
kapt("com.squareup.moshi:moshi-kotlin-codegen:1.13.0")
|
||||
|
||||
//Analytics
|
||||
implementation 'com.amplitude:android-sdk:3.35.1'
|
||||
|
|
@ -72,4 +72,22 @@ dependencies {
|
|||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
final File HRPG_PROPS_FILE = new File(projectDir.absolutePath + '/../habitica.properties')
|
||||
if (HRPG_PROPS_FILE.canRead()) {
|
||||
Properties HRPG_PROPS = new Properties()
|
||||
HRPG_PROPS.load(new FileInputStream(HRPG_PROPS_FILE))
|
||||
|
||||
if (HRPG_PROPS != null) {
|
||||
android.buildTypes.all { buildType ->
|
||||
HRPG_PROPS.any { property ->
|
||||
buildType.buildConfigField "String", property.key, "\"${property.value}\""
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new MissingResourceException('habitica.properties found but some entries are missing')
|
||||
}
|
||||
} else {
|
||||
throw new MissingResourceException('habitica.properties not found')
|
||||
}
|
||||
|
|
@ -35,6 +35,7 @@
|
|||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".ui.activities.TaskListActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
@ -96,4 +96,6 @@ class ApiClient @Inject constructor(
|
|||
suspend fun removePushDevice(id: String) = apiService.removePushDevice(id).data
|
||||
|
||||
suspend fun runCron() = apiService.runCron().data
|
||||
|
||||
suspend fun getTasks() = apiService.getTasks().data
|
||||
}
|
||||
|
|
@ -3,9 +3,9 @@ package com.habitrpg.wearos.habitica.data
|
|||
import com.habitrpg.common.habitica.models.auth.UserAuth
|
||||
import com.habitrpg.common.habitica.models.auth.UserAuthResponse
|
||||
import com.habitrpg.common.habitica.models.auth.UserAuthSocial
|
||||
import com.habitrpg.common.habitica.models.responses.HabitResponse
|
||||
import com.habitrpg.common.habitica.models.responses.TaskDirectionData
|
||||
import com.habitrpg.wearos.habitica.models.User
|
||||
import com.habitrpg.wearos.habitica.models.WearableHabitResponse
|
||||
import com.habitrpg.wearos.habitica.models.tasks.BulkTaskScoringData
|
||||
import com.habitrpg.wearos.habitica.models.tasks.Task
|
||||
import com.habitrpg.wearos.habitica.models.tasks.TaskList
|
||||
|
|
@ -20,74 +20,77 @@ import retrofit2.http.Query
|
|||
|
||||
interface ApiService {
|
||||
@GET("user/")
|
||||
suspend fun getUser(): HabitResponse<User>
|
||||
suspend fun getUser(): WearableHabitResponse<User>
|
||||
|
||||
@PUT("user/")
|
||||
suspend fun updateUser(@Body updateDictionary: Map<String, Any>): HabitResponse<User>
|
||||
suspend fun updateUser(@Body updateDictionary: Map<String, Any>): WearableHabitResponse<User>
|
||||
|
||||
@PUT("user/")
|
||||
suspend fun registrationLanguage(@Header("Accept-Language") registrationLanguage: String): HabitResponse<User>
|
||||
suspend fun registrationLanguage(@Header("Accept-Language") registrationLanguage: String): WearableHabitResponse<User>
|
||||
|
||||
@GET("tasks/user")
|
||||
suspend fun getTasks(@Query("type") type: String): HabitResponse<TaskList>
|
||||
suspend fun getTasks(): WearableHabitResponse<TaskList>
|
||||
|
||||
@GET("tasks/user")
|
||||
suspend fun getTasks(@Query("type") type: String, @Query("dueDate") dueDate: String): HabitResponse<TaskList>
|
||||
suspend fun getTasks(@Query("type") type: String): WearableHabitResponse<TaskList>
|
||||
|
||||
@GET("tasks/user")
|
||||
suspend fun getTasks(@Query("type") type: String, @Query("dueDate") dueDate: String): WearableHabitResponse<TaskList>
|
||||
|
||||
@GET("tasks/{id}")
|
||||
suspend fun getTask(@Path("id") id: String): HabitResponse<Task>
|
||||
suspend fun getTask(@Path("id") id: String): WearableHabitResponse<Task>
|
||||
|
||||
@POST("tasks/{id}/score/{direction}")
|
||||
suspend fun postTaskDirection(@Path("id") id: String, @Path("direction") direction: String): HabitResponse<TaskDirectionData>
|
||||
suspend fun postTaskDirection(@Path("id") id: String, @Path("direction") direction: String): WearableHabitResponse<TaskDirectionData>
|
||||
@POST("tasks/bulk-score")
|
||||
suspend fun bulkScoreTasks(@Body data: List<Map<String, String>>): HabitResponse<BulkTaskScoringData>
|
||||
suspend fun bulkScoreTasks(@Body data: List<Map<String, String>>): WearableHabitResponse<BulkTaskScoringData>
|
||||
|
||||
@POST("tasks/{id}/move/to/{position}")
|
||||
suspend fun postTaskNewPosition(@Path("id") id: String, @Path("position") position: Int): HabitResponse<List<String>>
|
||||
suspend fun postTaskNewPosition(@Path("id") id: String, @Path("position") position: Int): WearableHabitResponse<List<String>>
|
||||
|
||||
@POST("tasks/{taskId}/checklist/{itemId}/score")
|
||||
suspend fun scoreChecklistItem(@Path("taskId") taskId: String, @Path("itemId") itemId: String): HabitResponse<Task>
|
||||
suspend fun scoreChecklistItem(@Path("taskId") taskId: String, @Path("itemId") itemId: String): WearableHabitResponse<Task>
|
||||
|
||||
@POST("tasks/user")
|
||||
suspend fun createTask(@Body item: Task): HabitResponse<Task>
|
||||
suspend fun createTask(@Body item: Task): WearableHabitResponse<Task>
|
||||
|
||||
@POST("tasks/user")
|
||||
suspend fun createTasks(@Body tasks: List<Task>): HabitResponse<List<Task>>
|
||||
suspend fun createTasks(@Body tasks: List<Task>): WearableHabitResponse<List<Task>>
|
||||
|
||||
@PUT("tasks/{id}")
|
||||
suspend fun updateTask(@Path("id") id: String, @Body item: Task): HabitResponse<Task>
|
||||
suspend fun updateTask(@Path("id") id: String, @Body item: Task): WearableHabitResponse<Task>
|
||||
|
||||
@DELETE("tasks/{id}")
|
||||
suspend fun deleteTask(@Path("id") id: String): HabitResponse<Void>
|
||||
suspend fun deleteTask(@Path("id") id: String): WearableHabitResponse<Void>
|
||||
|
||||
@POST("user/auth/local/register")
|
||||
suspend fun registerUser(@Body auth: UserAuth): HabitResponse<UserAuthResponse>
|
||||
suspend fun registerUser(@Body auth: UserAuth): WearableHabitResponse<UserAuthResponse>
|
||||
|
||||
@POST("user/auth/local/login")
|
||||
suspend fun connectLocal(@Body auth: UserAuth): HabitResponse<UserAuthResponse>
|
||||
suspend fun connectLocal(@Body auth: UserAuth): WearableHabitResponse<UserAuthResponse>
|
||||
|
||||
@POST("user/auth/social")
|
||||
suspend fun connectSocial(@Body auth: UserAuthSocial): HabitResponse<UserAuthResponse>
|
||||
suspend fun connectSocial(@Body auth: UserAuthSocial): WearableHabitResponse<UserAuthResponse>
|
||||
|
||||
@DELETE("user/auth/social/{network}")
|
||||
suspend fun disconnectSocial(@Path("network") network: String): HabitResponse<Void>
|
||||
suspend fun disconnectSocial(@Path("network") network: String): WearableHabitResponse<Void>
|
||||
|
||||
@POST("user/auth/apple")
|
||||
suspend fun loginApple(@Body auth: Map<String, Any>): HabitResponse<UserAuthResponse>
|
||||
suspend fun loginApple(@Body auth: Map<String, Any>): WearableHabitResponse<UserAuthResponse>
|
||||
|
||||
@POST("user/sleep")
|
||||
suspend fun sleep(): HabitResponse<Boolean>
|
||||
suspend fun sleep(): WearableHabitResponse<Boolean>
|
||||
|
||||
@POST("user/revive")
|
||||
suspend fun revive(): HabitResponse<User>
|
||||
suspend fun revive(): WearableHabitResponse<User>
|
||||
|
||||
// Push notifications
|
||||
@POST("user/push-devices")
|
||||
suspend fun addPushDevice(@Body pushDeviceData: Map<String, String>): HabitResponse<List<Void>>
|
||||
suspend fun addPushDevice(@Body pushDeviceData: Map<String, String>): WearableHabitResponse<List<Void>>
|
||||
|
||||
@DELETE("user/push-devices/{regId}")
|
||||
suspend fun removePushDevice(@Path("regId") regId: String): HabitResponse<List<Void>>
|
||||
suspend fun removePushDevice(@Path("regId") regId: String): WearableHabitResponse<List<Void>>
|
||||
|
||||
@POST("cron")
|
||||
suspend fun runCron(): HabitResponse<Void>
|
||||
suspend fun runCron(): WearableHabitResponse<Void>
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package com.habitrpg.wearos.habitica.data
|
||||
|
||||
import android.os.Build
|
||||
import com.habitrpg.common.habitica.models.tasks.Attribute
|
||||
import com.habitrpg.common.habitica.models.tasks.Frequency
|
||||
import com.habitrpg.common.habitica.models.tasks.TaskType
|
||||
import com.squareup.moshi.FromJson
|
||||
import com.squareup.moshi.ToJson
|
||||
import java.text.DateFormat
|
||||
import java.text.ParseException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
|
||||
var customDateAdapter: Any = object : Any() {
|
||||
|
||||
@ToJson
|
||||
@Synchronized
|
||||
fun dateToJson(d: Date?): String? {
|
||||
return d?.let { dateFormats[0].format(it) }
|
||||
}
|
||||
|
||||
@FromJson
|
||||
@Synchronized
|
||||
@Throws(ParseException::class)
|
||||
fun dateFromJson(s: String?): Date? {
|
||||
var date: Date? = null
|
||||
var index = 0
|
||||
while (index < dateFormats.size && date == null) {
|
||||
try {
|
||||
date = dateFormats[index].parse(s)
|
||||
} catch (_: ParseException) {}
|
||||
index += 1
|
||||
}
|
||||
return date
|
||||
}
|
||||
|
||||
private var dateFormats = mutableListOf<DateFormat>()
|
||||
|
||||
init {
|
||||
addFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
|
||||
addFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
|
||||
addFormat("E MMM dd yyyy HH:mm:ss zzzz")
|
||||
addFormat("yyyy-MM-dd'T'HH:mm:sszzz")
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
addFormat("yyyy-MM-dd'T'HH:mmX")
|
||||
} else {
|
||||
addFormat("yyyy-MM-dd'T'HH:mm")
|
||||
}
|
||||
addFormat("yyyy-MM-dd")
|
||||
}
|
||||
|
||||
private fun addFormat(s: String) {
|
||||
val dateFormat = SimpleDateFormat(s, Locale.US)
|
||||
dateFormat.timeZone = TimeZone.getTimeZone("UTC")
|
||||
dateFormats.add(dateFormat)
|
||||
}
|
||||
}
|
||||
|
||||
class FrequencyAdapter {
|
||||
@ToJson
|
||||
fun toJson(type: Frequency): String = type.value
|
||||
@FromJson
|
||||
fun fromJson(value: String): Frequency? = Frequency.from(value)
|
||||
}
|
||||
|
||||
class TaskTypeAdapter {
|
||||
@ToJson
|
||||
fun toJson(type: TaskType): String = type.value
|
||||
@FromJson
|
||||
fun fromJson(value: String): TaskType? = TaskType.from(value)
|
||||
}
|
||||
|
||||
class AttributeAdapter {
|
||||
@ToJson
|
||||
fun toJson(type: Attribute): String = type.value
|
||||
@FromJson
|
||||
fun fromJson(value: String): Attribute? = Attribute.from(value)
|
||||
}
|
||||
|
|
@ -4,4 +4,7 @@ import com.habitrpg.wearos.habitica.data.ApiClient
|
|||
import javax.inject.Inject
|
||||
|
||||
class TaskRepository @Inject constructor(val apiClient: ApiClient, val localRepository: TaskLocalRepository) {
|
||||
|
||||
suspend fun retrieveTasks() = apiClient.getTasks()
|
||||
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.habitrpg.wearos.habitica.models
|
||||
|
||||
import com.habitrpg.common.habitica.models.AvatarBuffs
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
class Buffs: AvatarBuffs {
|
||||
override var con: Float? = null
|
||||
override var str: Float? = null
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package com.habitrpg.wearos.habitica.models
|
||||
|
||||
import com.habitrpg.common.habitica.models.AvatarFlags
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
class Flags: AvatarFlags {
|
||||
override var classSelected: Boolean = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package com.habitrpg.wearos.habitica.models
|
||||
|
||||
import com.habitrpg.common.habitica.models.AvatarHair
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
class Hair: AvatarHair {
|
||||
override var mustache: Int = 0
|
||||
override var beard: Int = 0
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package com.habitrpg.wearos.habitica.models
|
||||
|
||||
import com.habitrpg.common.habitica.models.AvatarOutfit
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
class Outfit: AvatarOutfit {
|
||||
override var armor: String = ""
|
||||
override var back: String = ""
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
package com.habitrpg.wearos.habitica.models
|
||||
|
||||
import com.habitrpg.common.habitica.models.AvatarHair
|
||||
import com.habitrpg.common.habitica.models.AvatarPreferences
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
class Preferences: AvatarPreferences {
|
||||
override val hair: Hair? = null
|
||||
override val costume: Boolean = false
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package com.habitrpg.wearos.habitica.models
|
||||
|
||||
import com.habitrpg.common.habitica.models.AvatarStats
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
class Stats: AvatarStats {
|
||||
override val buffs: Buffs? = null
|
||||
override var habitClass: String? = null
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
package com.habitrpg.wearos.habitica.models
|
||||
|
||||
import com.habitrpg.common.habitica.models.Avatar
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
open class Gear {
|
||||
var equipped: Outfit? = null
|
||||
var costume: Outfit? = null
|
||||
}
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
class Items {
|
||||
var gear: Gear? = null
|
||||
}
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
class User: Avatar {
|
||||
override val currentMount: String? = null
|
||||
override val currentPet: String? = null
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
package com.habitrpg.wearos.habitica.models
|
||||
|
||||
class WearableHabitResponse<T> {
|
||||
var data: T? = null
|
||||
var success: Boolean? = null
|
||||
var message: String? = null
|
||||
}
|
||||
|
|
@ -3,7 +3,9 @@ package com.habitrpg.wearos.habitica.models.tasks
|
|||
import com.habitrpg.common.habitica.models.responses.TaskDirectionData
|
||||
import com.habitrpg.wearos.habitica.models.Buffs
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
class BulkTaskScoringData {
|
||||
@Json(name="con")
|
||||
var constitution: Int? = null
|
||||
|
|
|
|||
|
|
@ -2,26 +2,19 @@ package com.habitrpg.wearos.habitica.models.tasks
|
|||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import com.squareup.moshi.JsonClass
|
||||
import java.util.UUID
|
||||
|
||||
open class ChecklistItem: Parcelable {
|
||||
|
||||
var id: String? = null
|
||||
var text: String? = null
|
||||
@JsonClass(generateAdapter = true)
|
||||
open class ChecklistItem constructor(
|
||||
var id: String? = UUID.randomUUID().toString(),
|
||||
var text: String? = null,
|
||||
var completed: Boolean = false
|
||||
) : Parcelable {
|
||||
|
||||
var position: Int = 0
|
||||
|
||||
@JvmOverloads constructor(id: String? = null, text: String? = null, completed: Boolean = false) {
|
||||
this.text = text
|
||||
if (id?.isNotEmpty() == true) {
|
||||
this.id = id
|
||||
} else {
|
||||
this.id = UUID.randomUUID().toString()
|
||||
}
|
||||
this.completed = completed
|
||||
}
|
||||
|
||||
constructor(item: ChecklistItem) {
|
||||
constructor(item: ChecklistItem) : this() {
|
||||
this.text = item.text
|
||||
this.id = item.id
|
||||
this.completed = item.completed
|
||||
|
|
@ -44,7 +37,7 @@ open class ChecklistItem: Parcelable {
|
|||
override fun newArray(size: Int): Array<ChecklistItem?> = arrayOfNulls(size)
|
||||
}
|
||||
|
||||
constructor(source: Parcel) {
|
||||
constructor(source: Parcel) : this() {
|
||||
id = source.readString()
|
||||
text = source.readString()
|
||||
completed = source.readByte() == 1.toByte()
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ package com.habitrpg.wearos.habitica.models.tasks
|
|||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
open class Days(): Parcelable {
|
||||
var m: Boolean = true
|
||||
var t: Boolean = true
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.habitrpg.wearos.habitica.models.tasks
|
|||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import com.squareup.moshi.JsonClass
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
|
|
@ -10,7 +11,8 @@ import java.time.format.DateTimeFormatter
|
|||
import java.time.format.DateTimeFormatterBuilder
|
||||
import java.time.temporal.TemporalAccessor
|
||||
|
||||
open class RemindersItem : Parcelable {
|
||||
@JsonClass(generateAdapter = true)
|
||||
open class RemindersItem constructor() : Parcelable {
|
||||
var id: String? = null
|
||||
var startDate: String? = null
|
||||
var time: String? = null
|
||||
|
|
@ -34,14 +36,12 @@ open class RemindersItem : Parcelable {
|
|||
override fun newArray(size: Int): Array<RemindersItem?> = arrayOfNulls(size)
|
||||
}
|
||||
|
||||
constructor(source: Parcel) {
|
||||
constructor(source: Parcel) : this() {
|
||||
id = source.readString()
|
||||
startDate = source.readString()
|
||||
time = source.readString()
|
||||
}
|
||||
|
||||
constructor()
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return if (other is RemindersItem) {
|
||||
this.id == other.id
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
package com.habitrpg.wearos.habitica.models.tasks
|
||||
|
||||
open class Tag {
|
||||
|
||||
var id: String = ""
|
||||
|
||||
var userId: String? = null
|
||||
var name: String = ""
|
||||
internal var challenge: Boolean = false
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other is Tag) {
|
||||
return this.id == other.id
|
||||
}
|
||||
return super.equals(other)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return id.hashCode()
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import com.habitrpg.common.habitica.models.tasks.Frequency
|
|||
import com.habitrpg.common.habitica.models.tasks.TaskType
|
||||
import com.habitrpg.wearos.habitica.R
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import java.time.LocalDateTime
|
||||
|
|
@ -21,7 +22,8 @@ import java.util.Calendar
|
|||
import java.util.Date
|
||||
import java.util.GregorianCalendar
|
||||
|
||||
open class Task : Parcelable {
|
||||
@JsonClass(generateAdapter = true)
|
||||
open class Task constructor(): Parcelable {
|
||||
|
||||
@Json(name="_id")
|
||||
var id: String? = null
|
||||
|
|
@ -32,7 +34,7 @@ open class Task : Parcelable {
|
|||
var type: TaskType?
|
||||
get() = TaskType.from(typeValue)
|
||||
set(value) { typeValue = value?.value }
|
||||
private var typeValue: String? = null
|
||||
internal var typeValue: String? = null
|
||||
var challengeID: String? = null
|
||||
var challengeBroken: String? = null
|
||||
var attribute: Attribute?
|
||||
|
|
@ -40,10 +42,8 @@ open class Task : Parcelable {
|
|||
set(value) { attributeValue = value?.value }
|
||||
var attributeValue: String? = Attribute.STRENGTH.value
|
||||
var value: Double = 0.0
|
||||
var tags: List<Tag>? = listOf()
|
||||
var dateCreated: Date? = null
|
||||
var position: Int = 0
|
||||
var group: TaskGroupPlan? = null
|
||||
// Habits
|
||||
var up: Boolean? = false
|
||||
var down: Boolean? = false
|
||||
|
|
@ -54,10 +54,7 @@ open class Task : Parcelable {
|
|||
var checklist: List<ChecklistItem>? = listOf()
|
||||
var reminders: List<RemindersItem>? = listOf()
|
||||
// dailies
|
||||
var frequency: Frequency?
|
||||
get() = Frequency.from(frequencyValue)
|
||||
set(value) { frequencyValue = value?.value }
|
||||
var frequencyValue: String? = null
|
||||
var frequency: Frequency? = null
|
||||
var everyX: Int? = 0
|
||||
var streak: Int? = 0
|
||||
var startDate: Date? = null
|
||||
|
|
@ -83,8 +80,8 @@ open class Task : Parcelable {
|
|||
var isCreating: Boolean = false
|
||||
var yesterDaily: Boolean = true
|
||||
|
||||
private var daysOfMonthString: String? = null
|
||||
private var weeksOfMonthString: String? = null
|
||||
internal var daysOfMonthString: String? = null
|
||||
internal var weeksOfMonthString: String? = null
|
||||
|
||||
@Json(ignore = true)
|
||||
private var daysOfMonth: List<Int>? = null
|
||||
|
|
@ -166,16 +163,6 @@ open class Task : Parcelable {
|
|||
val isChecklistDisplayActive: Boolean
|
||||
get() = this.checklist?.size != this.completedChecklistCount
|
||||
|
||||
val isGroupTask: Boolean
|
||||
get() = group?.groupID?.isNotBlank() == true
|
||||
|
||||
val isPendingApproval: Boolean
|
||||
get() = (group?.approvalRequired == true && group?.approvalRequested == true && group?.approvalApproved == false)
|
||||
|
||||
fun containsAllTagIds(tagIdList: List<String>): Boolean = tags?.mapTo(ArrayList()) { it.id }?.containsAll(tagIdList) ?: false
|
||||
|
||||
fun checkIfDue(): Boolean = isDue == true
|
||||
|
||||
fun getNextReminderOccurence(oldTime: String?): ZonedDateTime? {
|
||||
if (oldTime == null) {
|
||||
return null
|
||||
|
|
@ -269,7 +256,6 @@ open class Task : Parcelable {
|
|||
checklist != task.checklist -> return true
|
||||
priority != task.priority -> return true
|
||||
attribute != task.attribute && attribute != null -> return true
|
||||
tags != task.tags -> return true
|
||||
}
|
||||
if (type == TaskType.HABIT) {
|
||||
return when {
|
||||
|
|
@ -312,7 +298,6 @@ open class Task : Parcelable {
|
|||
dest.writeString(this.attribute?.value)
|
||||
dest.writeString(this.type?.value)
|
||||
dest.writeDouble(this.value)
|
||||
dest.writeList(this.tags as? List<*>)
|
||||
dest.writeLong(this.dateCreated?.time ?: -1)
|
||||
dest.writeInt(this.position)
|
||||
dest.writeValue(this.up)
|
||||
|
|
@ -334,9 +319,8 @@ open class Task : Parcelable {
|
|||
dest.writeInt(this.counterDown ?: 0)
|
||||
}
|
||||
|
||||
constructor()
|
||||
|
||||
protected constructor(`in`: Parcel) {
|
||||
protected constructor(`in`: Parcel): this() {
|
||||
this.userId = `in`.readString() ?: ""
|
||||
this.priority = `in`.readValue(Float::class.java.classLoader) as? Float ?: 0f
|
||||
this.text = `in`.readString() ?: ""
|
||||
|
|
@ -344,8 +328,6 @@ open class Task : Parcelable {
|
|||
this.attribute = Attribute.from(`in`.readString() ?: "")
|
||||
this.type = TaskType.from(`in`.readString() ?: "")
|
||||
this.value = `in`.readDouble()
|
||||
this.tags = listOf()
|
||||
`in`.readList(this.tags as List<*>, TaskTag::class.java.classLoader)
|
||||
val tmpDateCreated = `in`.readLong()
|
||||
this.dateCreated = if (tmpDateCreated == -1L) null else Date(tmpDateCreated)
|
||||
this.position = `in`.readInt()
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
package com.habitrpg.wearos.habitica.models.tasks
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import java.util.Date
|
||||
|
||||
open class TaskGroupPlan {
|
||||
|
||||
@Json(name="id")
|
||||
var groupID: String? = null
|
||||
var managerNotes: String? = null
|
||||
var sharedCompletion: String? = null
|
||||
var assignedDate: Date? = null
|
||||
var assigningUsername: String? = null
|
||||
var assignedUsers: List<String> = listOf()
|
||||
|
||||
var approvalRequested: Boolean = false
|
||||
var approvalApproved: Boolean = false
|
||||
var approvalRequired: Boolean = false
|
||||
}
|
||||
|
|
@ -1,5 +1,20 @@
|
|||
package com.habitrpg.wearos.habitica.models.tasks
|
||||
|
||||
class TaskList {
|
||||
var tasks: MutableMap<String, Task> = mutableMapOf()
|
||||
import com.squareup.moshi.FromJson
|
||||
import com.squareup.moshi.ToJson
|
||||
|
||||
class TaskList(var tasks: MutableMap<String, Task> = mutableMapOf())
|
||||
|
||||
class WrappedTasklistAdapter {
|
||||
@FromJson
|
||||
fun fromJson(json: List<Task>): TaskList {
|
||||
val tasks = mutableMapOf<String, Task>()
|
||||
json.forEach { tasks[it.id ?: ""] = it }
|
||||
return TaskList(tasks)
|
||||
}
|
||||
|
||||
@ToJson
|
||||
fun toJson(value: TaskList): List<Task> {
|
||||
return value.tasks.values.toList()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
package com.habitrpg.wearos.habitica.models.tasks
|
||||
|
||||
open class TaskTag {
|
||||
var tag: Tag? = null
|
||||
var task: Task? = null
|
||||
}
|
||||
|
|
@ -6,8 +6,15 @@ import androidx.preference.PreferenceManager
|
|||
import com.habitrpg.common.habitica.api.HostConfig
|
||||
import com.habitrpg.common.habitica.helpers.KeyHelper
|
||||
import com.habitrpg.shared.habitica.HLogger
|
||||
import com.habitrpg.wearos.habitica.BuildConfig
|
||||
import com.habitrpg.wearos.habitica.data.ApiClient
|
||||
import com.habitrpg.wearos.habitica.data.AttributeAdapter
|
||||
import com.habitrpg.wearos.habitica.data.FrequencyAdapter
|
||||
import com.habitrpg.wearos.habitica.data.TaskTypeAdapter
|
||||
import com.habitrpg.wearos.habitica.data.customDateAdapter
|
||||
import com.habitrpg.wearos.habitica.models.tasks.WrappedTasklistAdapter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -40,13 +47,19 @@ class AppModule {
|
|||
fun providesConverterFactory(): Converter.Factory {
|
||||
return MoshiConverterFactory.create(
|
||||
Moshi.Builder()
|
||||
.add(WrappedTasklistAdapter())
|
||||
.add(customDateAdapter)
|
||||
.add(FrequencyAdapter())
|
||||
.add(TaskTypeAdapter())
|
||||
.add(AttributeAdapter())
|
||||
.addLast(KotlinJsonAdapterFactory())
|
||||
.build()
|
||||
).asLenient()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesApiHelper(
|
||||
fun providesApiHClient(
|
||||
hostConfig: HostConfig,
|
||||
@ApplicationContext context: Context,
|
||||
converter: Converter.Factory
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
package com.habitrpg.wearos.habitica.ui.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.PersistableBundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.viewbinding.ViewBinding
|
||||
|
||||
open class BaseActivity<B: ViewBinding> : ComponentActivity() {
|
||||
protected lateinit var binding: B
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
|
||||
super.onCreate(savedInstanceState, persistentState)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(binding.root)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,136 @@
|
|||
package com.habitrpg.wearos.habitica.ui.activities
|
||||
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.wear.widget.WearableLinearLayoutManager
|
||||
import com.habitrpg.common.habitica.models.tasks.TaskType
|
||||
import com.habitrpg.wearos.habitica.R
|
||||
import com.habitrpg.wearos.habitica.databinding.ActivityMainBinding
|
||||
import com.habitrpg.wearos.habitica.ui.adapters.HubAdapter
|
||||
import com.habitrpg.wearos.habitica.ui.viewmodels.MainViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlin.math.abs
|
||||
|
||||
data class MenuItem(
|
||||
val identifier: String,
|
||||
val title: String,
|
||||
val icon: Drawable?,
|
||||
val onClick: () -> Unit
|
||||
)
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
val viewModel: MainViewModel by viewModels()
|
||||
|
||||
private val adapter = HubAdapter()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
super.onCreate(savedInstanceState)
|
||||
binding.root.apply {
|
||||
layoutManager =
|
||||
WearableLinearLayoutManager(this@MainActivity, HabiticaScrollingLayoutCallback())
|
||||
adapter = this@MainActivity.adapter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
binding.root.post {
|
||||
binding.root.setPaddingRelative(0, (binding.root.height * 0.25).toInt(), 0, (binding.root.height * 0.25).toInt())
|
||||
binding.root.scrollY = 0
|
||||
}
|
||||
adapter.data = listOf(
|
||||
MenuItem(
|
||||
"avatar",
|
||||
"Avatar",
|
||||
AppCompatResources.getDrawable(this, R.drawable.icon_rewards)
|
||||
) {
|
||||
|
||||
},
|
||||
MenuItem(
|
||||
"Stats",
|
||||
getString(R.string.stats),
|
||||
AppCompatResources.getDrawable(this, R.drawable.icon_rewards)
|
||||
) {
|
||||
|
||||
},
|
||||
MenuItem(
|
||||
"habits",
|
||||
getString(R.string.habits),
|
||||
AppCompatResources.getDrawable(this, R.drawable.icon_habits)
|
||||
) {
|
||||
openTasklist(TaskType.HABIT)
|
||||
},
|
||||
MenuItem(
|
||||
"dailies",
|
||||
getString(R.string.dailies),
|
||||
AppCompatResources.getDrawable(this, R.drawable.icon_dailies)
|
||||
) {
|
||||
openTasklist(TaskType.DAILY)
|
||||
},
|
||||
MenuItem(
|
||||
"todos",
|
||||
getString(R.string.todos),
|
||||
AppCompatResources.getDrawable(this, R.drawable.icon_todos)
|
||||
) {
|
||||
openTasklist(TaskType.TODO)
|
||||
},
|
||||
MenuItem(
|
||||
"rewards",
|
||||
getString(R.string.rewards),
|
||||
AppCompatResources.getDrawable(this, R.drawable.icon_rewards)
|
||||
) {
|
||||
openTasklist(TaskType.REWARD)
|
||||
}
|
||||
)
|
||||
viewModel.user.observe(this) {
|
||||
Log.d("MainActivity", "onStart: ${it.currentPet}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun openTasklist(type: TaskType) {
|
||||
val intent = Intent(this, TaskListActivity::class.java).apply {
|
||||
putExtra("type", type.name)
|
||||
}
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
private const val MAX_ICON_PROGRESS = 0.8f
|
||||
|
||||
class HabiticaScrollingLayoutCallback : WearableLinearLayoutManager.LayoutCallback() {
|
||||
|
||||
private var progressToCenter: Float = 0f
|
||||
|
||||
override fun onLayoutFinished(child: View, parent: RecyclerView) {
|
||||
child.apply {
|
||||
// Figure out % progress from top to bottom
|
||||
val centerOffset = height.toFloat() / 2.0f / parent.height.toFloat()
|
||||
val yRelativeToCenterOffset = y / parent.height + centerOffset
|
||||
|
||||
// Normalize for center
|
||||
progressToCenter = abs(0.5f - yRelativeToCenterOffset) - 0.25f
|
||||
if (progressToCenter < 0) {
|
||||
scaleX = 1f
|
||||
scaleY = 1f
|
||||
alpha = 1f
|
||||
return
|
||||
}
|
||||
// Adjust to the maximum scale
|
||||
progressToCenter = Math.min(progressToCenter * 1.5f, MAX_ICON_PROGRESS)
|
||||
|
||||
scaleX = 1 - progressToCenter
|
||||
scaleY = 1 - progressToCenter
|
||||
alpha = 1 - progressToCenter * 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.habitrpg.wearos.habitica.ui.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.viewModels
|
||||
import androidx.wear.widget.WearableLinearLayoutManager
|
||||
import com.habitrpg.wearos.habitica.databinding.ActivityTasklistBinding
|
||||
import com.habitrpg.wearos.habitica.models.tasks.Task
|
||||
import com.habitrpg.wearos.habitica.ui.adapters.TaskListAdapter
|
||||
import com.habitrpg.wearos.habitica.ui.viewmodels.TaskListViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class TaskListActivity: BaseActivity<ActivityTasklistBinding>() {
|
||||
private val adapter = TaskListAdapter()
|
||||
private val viewModel: TaskListViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
binding = ActivityTasklistBinding.inflate(layoutInflater)
|
||||
super.onCreate(savedInstanceState)
|
||||
binding.root.apply {
|
||||
isEdgeItemsCenteringEnabled = true
|
||||
layoutManager =
|
||||
WearableLinearLayoutManager(this@TaskListActivity, HabiticaScrollingLayoutCallback())
|
||||
adapter = this@TaskListActivity.adapter
|
||||
}
|
||||
|
||||
adapter.data = listOf(
|
||||
Task().apply { text = "Test 1" },
|
||||
Task().apply { text = "Test 2" },
|
||||
Task().apply { text = "Test 3" },
|
||||
Task().apply { text = "Test 4" },
|
||||
Task().apply { text = "Test 5" }
|
||||
)
|
||||
|
||||
viewModel.tasks.observe(this) {
|
||||
adapter.data = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.habitrpg.wearos.habitica.ui.adapters
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.habitrpg.common.habitica.extensions.layoutInflater
|
||||
import com.habitrpg.wearos.habitica.databinding.RowHubBinding
|
||||
import com.habitrpg.wearos.habitica.ui.activities.MenuItem
|
||||
|
||||
class HubAdapter: RecyclerView.Adapter<HubViewHolder>() {
|
||||
var data: List<MenuItem> = listOf()
|
||||
set(value) {
|
||||
field = value
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HubViewHolder {
|
||||
return HubViewHolder(RowHubBinding.inflate(parent.context.layoutInflater, parent, false).root)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: HubViewHolder, position: Int) {
|
||||
holder.bind(data[position])
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return data.size
|
||||
}
|
||||
}
|
||||
|
||||
class HubViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
|
||||
val binding = RowHubBinding.bind(itemView)
|
||||
|
||||
fun bind(item: MenuItem) {
|
||||
binding.title.text = item.title
|
||||
binding.iconView.setImageDrawable(item.icon)
|
||||
binding.root.setOnClickListener {
|
||||
item.onClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.habitrpg.wearos.habitica.ui.adapters
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.habitrpg.common.habitica.extensions.layoutInflater
|
||||
import com.habitrpg.wearos.habitica.databinding.RowHabitBinding
|
||||
import com.habitrpg.wearos.habitica.models.tasks.Task
|
||||
|
||||
class TaskListAdapter: RecyclerView.Adapter<TaskViewHolder>() {
|
||||
var data: List<Task> = listOf()
|
||||
set(value) {
|
||||
field = value
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TaskViewHolder {
|
||||
return TaskViewHolder(RowHabitBinding.inflate(parent.context.layoutInflater, parent, false).root)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: TaskViewHolder, position: Int) {
|
||||
holder.bind(data[position])
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return data.size
|
||||
}
|
||||
}
|
||||
|
||||
class TaskViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
val binding = RowHabitBinding.bind(itemView)
|
||||
|
||||
fun bind(task: Task) {
|
||||
binding.title.text = task.text
|
||||
}
|
||||
}
|
||||
|
|
@ -2,11 +2,6 @@ package com.habitrpg.wearos.habitica.ui.viewmodels
|
|||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.habitrpg.wearos.habitica.data.repositories.UserRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
open class BaseViewModel: ViewModel() {
|
||||
@Inject
|
||||
lateinit var repository: UserRepository
|
||||
open class BaseViewModel(val userRepository: UserRepository): ViewModel() {
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.habitrpg.wearos.habitica.ui.viewmodels
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.habitrpg.wearos.habitica.data.repositories.UserRepository
|
||||
import com.habitrpg.wearos.habitica.models.User
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class MainViewModel @Inject constructor(userRepository: UserRepository) : BaseViewModel(userRepository) {
|
||||
val user = MutableLiveData<User>()
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
user.value = userRepository.retrieveUser()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.habitrpg.wearos.habitica.ui.viewmodels
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.habitrpg.wearos.habitica.data.repositories.TaskRepository
|
||||
import com.habitrpg.wearos.habitica.data.repositories.UserRepository
|
||||
import com.habitrpg.wearos.habitica.models.tasks.Task
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class TaskListViewModel @Inject constructor(
|
||||
private val taskRepository: TaskRepository,
|
||||
userRepository: UserRepository
|
||||
) : BaseViewModel(userRepository) {
|
||||
val tasks = MutableLiveData<List<Task>>()
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
tasks.value = taskRepository.retrieveTasks()?.tasks?.values?.toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
5
wearos/src/main/res/drawable/row_background.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<corners android:radius="40dp" />
|
||||
<solid android:color="@color/gray_100" />
|
||||
</shape>
|
||||
|
|
@ -1,21 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.wear.widget.BoxInsetLayout
|
||||
<androidx.wear.widget.WearableRecyclerView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.activities.MainActivity"
|
||||
tools:deviceIds="wear">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_boxedEdges="all">
|
||||
|
||||
<com.habitrpg.common.habitica.views.AvatarView
|
||||
android:id="@+id/avatar_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</FrameLayout>
|
||||
</androidx.wear.widget.BoxInsetLayout>
|
||||
</androidx.wear.widget.WearableRecyclerView>
|
||||
6
wearos/src/main/res/layout/activity_tasklist.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.wear.widget.WearableRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.wear.widget.WearableRecyclerView>
|
||||
19
wearos/src/main/res/layout/row_habit.xml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="@dimen/spacing_medium"
|
||||
android:paddingVertical="2dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/row_background"
|
||||
android:padding="@dimen/spacing_medium"
|
||||
android:gravity="center">
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
26
wearos/src/main/res/layout/row_hub.xml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="@dimen/spacing_medium"
|
||||
android:paddingVertical="2dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/row_background"
|
||||
android:padding="@dimen/spacing_medium"
|
||||
android:gravity="center">
|
||||
<ImageView
|
||||
android:id="@+id/icon_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/icon_habits"
|
||||
android:paddingEnd="@dimen/spacing_medium"
|
||||
android:paddingStart="0dp"/>
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
<resources>
|
||||
<string name="hello_world">Hello Round World!</string>
|
||||
</resources>
|
||||
|
|
@ -1,8 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">Habitica</string>
|
||||
<!--
|
||||
This string is used for square devices and overridden by hello_world in
|
||||
values-round/strings.xml for round devices.
|
||||
-->
|
||||
<string name="hello_world">Hello Square World!</string>
|
||||
</resources>
|
||||