start implementing new post widget

Signed-off-by: Christine Dodrill <me@christine.website>
This commit is contained in:
Cadey Ratio 2021-07-05 17:03:02 -04:00
parent 4970df45e3
commit 510ec72811
15 changed files with 302 additions and 47 deletions

View File

@ -17,6 +17,7 @@
import groovy.xml.MarkupBuilder import groovy.xml.MarkupBuilder
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
def twaManifest = [ def twaManifest = [
applicationId: 'website.christine.xesite', applicationId: 'website.christine.xesite',
@ -153,6 +154,9 @@ android {
lintOptions { lintOptions {
checkReleaseBuilds false checkReleaseBuilds false
} }
buildFeatures {
viewBinding true
}
} }
task generateShorcutsFile { task generateShorcutsFile {
@ -202,5 +206,6 @@ dependencies {
implementation 'com.google.androidbrowserhelper:locationdelegation:1.0.0' implementation 'com.google.androidbrowserhelper:locationdelegation:1.0.0'
implementation 'com.google.androidbrowserhelper:androidbrowserhelper:2.2.0' implementation 'com.google.androidbrowserhelper:androidbrowserhelper:2.2.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'com.android.volley:volley:1.2.0'
} }

View File

@ -1,48 +1,39 @@
<!-- <?xml version="1.0" encoding="utf-8"?>
Copyright 2019 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- The "package" attribute is rewritten by the Gradle build with the value of applicationId.
It is still required here, as it is used to derive paths, for instance when referring
to an Activity by ".MyActivity" instead of the full name. If more Activities are added to the
application, the package attribute will need to reflect the correct path in order to use
the abbreviated format. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="website.christine.xesite"> package="website.christine.xesite">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<application <application
android:name="Application" android:name=".Application"
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/appName" android:label="@string/appName"
android:manageSpaceActivity="com.google.androidbrowserhelper.trusted.ManageDataLauncherActivity" android:manageSpaceActivity="com.google.androidbrowserhelper.trusted.ManageDataLauncherActivity"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@android:style/Theme.Translucent.NoTitleBar"> android:theme="@android:style/Theme.Translucent.NoTitleBar">
<receiver android:name=".CurrentPostWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/current_post_widget_info" />
</receiver>
<activity android:name=".CurrentPostWidgetConfigureActivity">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<meta-data <meta-data
android:name="asset_statements" android:name="asset_statements"
android:resource="@string/assetStatements" /> android:resource="@string/assetStatements" />
<meta-data <meta-data
android:name="web_manifest_url" android:name="web_manifest_url"
android:value="@string/webManifestUrl" /> android:value="@string/webManifestUrl" />
<meta-data <meta-data
android:name="twa_generator" android:name="twa_generator"
android:value="@string/generatorApp" /> android:value="@string/generatorApp" />
@ -52,69 +43,56 @@
android:name="android.support.customtabs.trusted.MANAGE_SPACE_URL" android:name="android.support.customtabs.trusted.MANAGE_SPACE_URL"
android:value="@string/launchUrl" /> android:value="@string/launchUrl" />
</activity> </activity>
<activity <activity
android:name="LauncherActivity" android:name=".LauncherActivity"
android:alwaysRetainTaskState="true" android:alwaysRetainTaskState="true"
android:label="@string/launcherName" android:label="@string/launcherName"
android:screenOrientation="unspecified"> android:screenOrientation="unspecified">
<meta-data <meta-data
android:name="android.support.customtabs.trusted.DEFAULT_URL" android:name="android.support.customtabs.trusted.DEFAULT_URL"
android:value="@string/launchUrl" /> android:value="@string/launchUrl" />
<meta-data <meta-data
android:name="android.support.customtabs.trusted.STATUS_BAR_COLOR" android:name="android.support.customtabs.trusted.STATUS_BAR_COLOR"
android:resource="@color/colorPrimary" /> android:resource="@color/colorPrimary" />
<meta-data <meta-data
android:name="android.support.customtabs.trusted.NAVIGATION_BAR_COLOR" android:name="android.support.customtabs.trusted.NAVIGATION_BAR_COLOR"
android:resource="@color/navigationColor" /> android:resource="@color/navigationColor" />
<meta-data <meta-data
android:name="android.support.customtabs.trusted.NAVIGATION_BAR_COLOR_DARK" android:name="android.support.customtabs.trusted.NAVIGATION_BAR_COLOR_DARK"
android:resource="@color/navigationColorDark" /> android:resource="@color/navigationColorDark" />
<meta-data <meta-data
android:name="androix.browser.trusted.NAVIGATION_BAR_DIVIDER_COLOR" android:name="androix.browser.trusted.NAVIGATION_BAR_DIVIDER_COLOR"
android:resource="@color/navigationDividerColor" /> android:resource="@color/navigationDividerColor" />
<meta-data <meta-data
android:name="androix.browser.trusted.NAVIGATION_BAR_DIVIDER_COLOR_DARK" android:name="androix.browser.trusted.NAVIGATION_BAR_DIVIDER_COLOR_DARK"
android:resource="@color/navigationDividerColorDark" /> android:resource="@color/navigationDividerColorDark" />
<meta-data <meta-data
android:name="android.support.customtabs.trusted.SPLASH_IMAGE_DRAWABLE" android:name="android.support.customtabs.trusted.SPLASH_IMAGE_DRAWABLE"
android:resource="@drawable/splash" /> android:resource="@drawable/splash" />
<meta-data <meta-data
android:name="android.support.customtabs.trusted.SPLASH_SCREEN_BACKGROUND_COLOR" android:name="android.support.customtabs.trusted.SPLASH_SCREEN_BACKGROUND_COLOR"
android:resource="@color/backgroundColor" /> android:resource="@color/backgroundColor" />
<meta-data <meta-data
android:name="android.support.customtabs.trusted.SPLASH_SCREEN_FADE_OUT_DURATION" android:name="android.support.customtabs.trusted.SPLASH_SCREEN_FADE_OUT_DURATION"
android:value="@integer/splashScreenFadeOutDuration" /> android:value="@integer/splashScreenFadeOutDuration" />
<meta-data <meta-data
android:name="android.support.customtabs.trusted.FILE_PROVIDER_AUTHORITY" android:name="android.support.customtabs.trusted.FILE_PROVIDER_AUTHORITY"
android:value="@string/providerAuthority" /> android:value="@string/providerAuthority" />
<meta-data <meta-data
android:name="android.app.shortcuts" android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" /> android:resource="@xml/shortcuts" />
<meta-data <meta-data
android:name="android.support.customtabs.trusted.FALLBACK_STRATEGY" android:name="android.support.customtabs.trusted.FALLBACK_STRATEGY"
android:value="@string/fallbackType" /> android:value="@string/fallbackType" />
<meta-data <meta-data
android:name="android.support.customtabs.trusted.SCREEN_ORIENTATION" android:name="android.support.customtabs.trusted.SCREEN_ORIENTATION"
android:value="@string/orientation" /> android:value="@string/orientation" />
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
<intent-filter android:autoVerify="true"> <intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -126,9 +104,7 @@
android:scheme="https" /> android:scheme="https" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="com.google.androidbrowserhelper.trusted.FocusActivity" /> <activity android:name="com.google.androidbrowserhelper.trusted.FocusActivity" />
<activity <activity
android:name="com.google.androidbrowserhelper.trusted.WebViewFallbackActivity" android:name="com.google.androidbrowserhelper.trusted.WebViewFallbackActivity"
android:configChanges="orientation|screenSize" /> android:configChanges="orientation|screenSize" />
@ -147,14 +123,14 @@
android:name=".DelegationService" android:name=".DelegationService"
android:enabled="@bool/enableNotification" android:enabled="@bool/enableNotification"
android:exported="@bool/enableNotification"> android:exported="@bool/enableNotification">
<intent-filter> <intent-filter>
<action android:name="android.support.customtabs.trusted.TRUSTED_WEB_ACTIVITY_SERVICE" /> <action android:name="android.support.customtabs.trusted.TRUSTED_WEB_ACTIVITY_SERVICE" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</service> </service>
<activity android:name="com.google.androidbrowserhelper.locationdelegation.PermissionRequestActivity" /> <activity android:name="com.google.androidbrowserhelper.locationdelegation.PermissionRequestActivity" />
</application> </application>
</manifest>
</manifest>

View File

@ -0,0 +1,44 @@
package website.christine.xesite
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.widget.RemoteViews
/**
* Implementation of App Widget functionality.
* App Widget Configuration implemented in [CurrentPostWidgetConfigureActivity]
*/
class CurrentPostWidget : AppWidgetProvider() {
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
// There may be multiple widgets active, so update all of them
for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
}
override fun onDeleted(context: Context, appWidgetIds: IntArray) {
// When the user deletes the widget, delete the preference associated with it.
for (appWidgetId in appWidgetIds) {
deleteTitlePref(context, appWidgetId)
}
}
override fun onEnabled(context: Context) {
// Enter relevant functionality for when the first widget is created
}
override fun onDisabled(context: Context) {
// Enter relevant functionality for when the last widget is disabled
}
}
internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
val widgetText = loadTitlePref(context, appWidgetId)
// Construct the RemoteViews object
val views = RemoteViews(context.packageName, R.layout.current_post_widget)
views.setTextViewText(R.id.appwidget_text, widgetText)
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views)
}

View File

@ -0,0 +1,103 @@
package website.christine.xesite
import android.app.Activity
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.EditText
import website.christine.xesite.databinding.CurrentPostWidgetConfigureBinding
/**
* The configuration screen for the [CurrentPostWidget] AppWidget.
*/
class CurrentPostWidgetConfigureActivity : Activity() {
private var appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID
private lateinit var appWidgetText: EditText
private var onClickListener = View.OnClickListener {
val context = this@CurrentPostWidgetConfigureActivity
// When the button is clicked, store the string locally
val widgetText = appWidgetText.text.toString()
saveTitlePref(context, appWidgetId, widgetText)
// It is the responsibility of the configuration activity to update the app widget
val appWidgetManager = AppWidgetManager.getInstance(context)
updateAppWidget(context, appWidgetManager, appWidgetId)
// Make sure we pass back the original appWidgetId
val resultValue = Intent()
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
setResult(RESULT_OK, resultValue)
finish()
}
private lateinit var binding: CurrentPostWidgetConfigureBinding
public override fun onCreate(icicle: Bundle?) {
super.onCreate(icicle)
// Set the result to CANCELED. This will cause the widget host to cancel
// out of the widget placement if the user presses the back button.
setResult(RESULT_CANCELED)
binding = CurrentPostWidgetConfigureBinding.inflate(layoutInflater)
setContentView(binding.root)
appWidgetText = binding.appwidgetText as EditText
binding.addButton.setOnClickListener(onClickListener)
// Find the widget id from the intent.
val intent = intent
val extras = intent.extras
if (extras != null) {
appWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID)
}
// If this activity was started with an intent without an app widget ID, finish with an error.
if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
finish()
return
}
appWidgetText.setText(loadTitlePref(this@CurrentPostWidgetConfigureActivity, appWidgetId))
}
}
private const val PREFS_NAME = "website.christine.xesite.CurrentPostWidget"
private const val PREF_PREFIX_KEY = "appwidget_"
internal fun savePref(ctx: Context, key: String, value: String) {
val prefs = ctx.getSharedPreferences(PREFS_NAME, 0).edit()
prefs.putString(PREF_PREFIX_KEY + key, value)
prefs.apply()
}
internal fun loadPref(ctx: Context, key: String, default: String): String {
val prefs = ctx.getSharedPreferences(PREFS_NAME, 0)
val titleValue = prefs.getString(PREF_PREFIX_KEY + key, null)
return titleValue ?: default
}
// Write the prefix to the SharedPreferences object for this widget
internal fun saveTitlePref(context: Context, appWidgetId: Int, text: String) {
val prefs = context.getSharedPreferences(PREFS_NAME, 0).edit()
prefs.putString(PREF_PREFIX_KEY + appWidgetId, text)
prefs.apply()
}
// Read the prefix from the SharedPreferences object for this widget.
// If there is no preference saved, get the default from a resource
internal fun loadTitlePref(context: Context, appWidgetId: Int): String {
val prefs = context.getSharedPreferences(PREFS_NAME, 0)
val titleValue = prefs.getString(PREF_PREFIX_KEY + appWidgetId, null)
return titleValue ?: context.getString(R.string.appwidget_text)
}
internal fun deleteTitlePref(context: Context, appWidgetId: Int) {
val prefs = context.getSharedPreferences(PREFS_NAME, 0).edit()
prefs.remove(PREF_PREFIX_KEY + appWidgetId)
prefs.apply()
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1,37 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/appWidgetBackgroundColor"
android:padding="@dimen/widget_margin"
android:theme="@style/ThemeOverlay.Xesite_android.AppWidgetContainer">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageView"
android:layout_width="92dp"
android:layout_height="wrap_content"
android:src="@drawable/splash" />
<TextView
android:id="@+id/appwidget_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="?attr/appWidgetBackgroundColor"
android:contentDescription="@string/appwidget_text"
android:text="@string/appwidget_text"
android:textColor="?attr/appWidgetTextColor"
android:textSize="24sp"
android:textStyle="bold|italic" />
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="@string/configure" />
<EditText
android:id="@+id/appwidget_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
<Button
android:id="@+id/add_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/add_widget" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/splash" />
</LinearLayout>

View File

@ -0,0 +1,7 @@
<resources>
<style name="ThemeOverlay.Xesite_android.AppWidgetContainer" parent="">
<item name="appWidgetBackgroundColor">@color/light_blue_900</item>
<item name="appWidgetTextColor">@color/light_blue_200</item>
</style>
</resources>

View File

@ -0,0 +1,6 @@
<resources>
<declare-styleable name="AppWidgetAttrs">
<attr name="appWidgetBackgroundColor" format="color" />
<attr name="appWidgetTextColor" format="color" />
</declare-styleable>
</resources>

View File

@ -15,4 +15,8 @@
--> -->
<resources> <resources>
<color name="shortcut_background">#F5F5F5</color> <color name="shortcut_background">#F5F5F5</color>
<color name="light_blue_50">#FFE1F5FE</color>
<color name="light_blue_200">#FF81D4FA</color>
<color name="light_blue_600">#FF039BE5</color>
<color name="light_blue_900">#FF01579B</color>
</resources> </resources>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
Refer to App Widget Documentation for margin information
http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
-->
<dimen name="widget_margin">0dp</dimen>
</resources>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="appwidget_text">EXAMPLE</string>
<string name="configure">Configure</string>
<string name="add_widget">Add widget</string>
<string name="text_text">Test text to see if I can do this.</string>
</resources>

View File

@ -0,0 +1,7 @@
<resources>
<style name="ThemeOverlay.Xesite_android.AppWidgetContainer" parent="">
<item name="appWidgetBackgroundColor">@color/light_blue_600</item>
<item name="appWidgetTextColor">@color/light_blue_50</item>
</style>
</resources>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:configure="website.christine.xesite.CurrentPostWidgetConfigureActivity"
android:initialKeyguardLayout="@layout/current_post_widget"
android:initialLayout="@layout/current_post_widget"
android:minWidth="250dp"
android:minHeight="40dp"
android:previewImage="@drawable/example_appwidget_preview"
android:resizeMode="horizontal"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen"></appwidget-provider>

View File

@ -18,12 +18,16 @@
buildscript { buildscript {
ext {
kotlin_version = '1.5.0'
}
repositories { repositories {
google() google()
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.2.1' classpath 'com.android.tools.build:gradle:4.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files